농산물 직거래 플랫폼 및 농사 용품 판매 쇼핑몰
FarmFarm 바로가기
최근 귀농, 숲세권 등의 단어에서 보여지듯이 자연에 대한 관심 증가하고 있다.
작게는 집 베란다 화분에서부터 나아가서는 주말농장, 텃밭 등 자연을 찾는 수요 또한 늘어나고 있다.
이뿐만 아니라 팬데믹으로 인해 건강에 관한 관심이 증가하면서 바른 먹거리와 깨끗한 농산물을 찾는 사람들이 많아졌고,
건강한 먹거리를 살 수 있는 소비자와 건강한 먹거리를 팔 수 있는 생산자 모두를 위한 사이트의 필요성을 자각하게 되었다.
FarmFarm(팜팜) 은 이러한 수요와 생산을 접목하면서 시작되었다.
건강한 먹거리를 사고파는 플랫폼에서 멈추지 않고, 먹거리를 직접 기르는 사람들에게까지도 도움이 될 수 있는 플램폼을 추구한다.
팜팜은
소비자 로서 건강한 먹거리를 구매하고,
판매자 로서 직접 기른 농작물을 직접 판매하고,
생산자 로서 농사에 필요한 농자재 구매 및 정보를 공유하는
All in One 거래 중개 플랫폼이다.
💡BenchMarking💡
농직, 마켓컬리, 당근마켓, 쿠팡 등
-
제작 기간 : 2022년 12월 12일 ~ 2023년 1월 11일
-
참여 인원 : 6인 팀 프로젝트
-
프로젝트 개요
- Java와 Spring 프레임워크를 이용하여 온라인 쇼핑몰 구축
- 상품 정보, 주문 정보, 회원 정보 등을 관리하는 기능 제공
- 개인간 거래, 커뮤니티 게시판, 채팅 및 알림 기능 제공
-
담당 기능
- 전체 프로젝트 기획 및 개발 참여
- 일반 회원, 판매자, 게시글, 댓글 등 대상별 신고 기능 구현
- 관리자 페이지의 편의성 향상을 위해 AJAX/AXIOS를 활용한 기능 구현
- 회원 관리 : 판매자 등록 상태, 회원 활동 상태에 따른 비동기 조회
- 신고 관리 : 강제 탈퇴, 정지, 게시글 삭제 등 신고 처리 기능 구현
- 필터, 정렬, 페이지네이션, 검색 기능
- @Scheduled를 활용하여 정지 계정 자동 활성화
- Chart.js를 활용한 관리자 대시보드 통계 그래프 구현
-
성과
- 온라인 쇼핑몰 프로토타입 완성
- 교육원 내 프로젝트 최우수상 수상
4.1. 신고하기
- 주소의 pathname을 이용하여 조건을 분리하였다.
- 판매자(seller), 판매 게시글(post), 채팅 회원(chat)
▼ JS 코드
// pathname: 각 기능 메인 주소
var pathname = location.pathname.substring(1, location.pathname.lastIndexOf("/"));
// postNo(판매글), seller에서 memberNo(판매자)
var targetNo = location.pathname.substring(location.pathname.lastIndexOf("/")+1);
var reportType;
var reportTargetNo;
// 신고하기 버튼 클릭 시
reportBtn.addEventListener("click", () => {
if(reportTargetNo == 0){
messageModalOpen("관리자는 신고 대상이 아닙니다.");
} else{
openReportModal(); // 신고하기 모달 열리고 → 신고 사유 등 선택한 뒤 신고버튼 누르면 report() 함수 선언
switch(pathname){
case 'seller': reportType = 'M'; reportTargetNo = targetNo; break;
case 'post': reportType = 'P'; reportTargetNo = targetNo; break;
case 'chat': reportType = 'M'; reportTargetNo = selectedChatNo; break; // chatContext.js에서 선언한 변수 사용
}
}
});
- 각 대상의 식별 번호을 이용하였다.
- 커뮤니티 게시글 작성자 (회원 번호), 커뮤니티 게시글 (게시글 번호), 커뮤니티 댓글 (댓글 번호) 신고
※ 페이지 안에 신고 대상이 여러 개이기 때문에 (1)의 방법처럼 pathname으로 신고 대상을 구분하기가 쉽지 않았다.
이에 각 대상별로 조건을 나누어서 구현하는 방법을 택하였다.
JS 코드
// 1) 댓글 신고
for(let i=0; i<reportCommentBtn.length; i++){
// 댓글의 신고하기 버튼 누르면 (본인의 댓글인 경우, 화면에서 신고하기 버튼 제거)
reportCommentBtn[i]. addEventListener("click", () => {
// 신고 모달 열리기
openReportModal();
// 각 댓글의 댓글 번호
const targetCommentNo = document.getElementsByClassName('targetCommentNo');
// 신고유형, 신고번호 매칭
if(targetCommentNo[i] != null){
reportType = 'C';
reportTargetNo = targetCommentNo[i].value;
}
})
}
// 2) 댓글 작성자 신고
document.getElementById('reportMemberBtn').addEventListener('click', () =>{
// memberNo = "${loginMember.memberNo}";
// 본인 계정 신고x
if(targetMemberNo != null && targetMemberNo != memberNo){
// 신고 모달 열리기
openReportModal();
reportType = 'M';
reportTargetNo = targetMemberNo;
}
if(targetMemberNo == memberNo){
messageModalOpen("본인의 계정은 신고할 수 없습니다.");
}
})
// 3) 커뮤니티 게시글 신고
document.getElementById('reportBoardBtn').addEventListener('click', () => {
if(boardNo != null){
// 신고 모달 열리기
openReportModal();
reportType = 'B';
reportTargetNo = boardNo;
}
})
- 신고하기를 클릭하면, 신고 사유를 입력하는 모달창이 열리게 되고
- 이 모달창에서 신고하기를 누르면 신고 사유와 함께 신고 기능이 처리된다.
-
신고 대상의 번호(reportTargetNo), 계정/게시글 등 신고 대상의 타입(reportType), 신고자가 선택한 신고 사유(reportReason) 및
작성한 신고 사유(reportContent)를 담아 컨트롤러에 전달하였고, 이를 신고 테이블에 insert 하였다.
신고 기능 JS
// 신고하기 ajax
var report = () => {
$.ajax({
url: "/report",
data: { "reportType" :reportType,
"reportTargetNo" : reportTargetNo,
"reportReason" : radioResult,
"reportContent": reportContent.value},
type: "POST",
success: (result) => {
if(result > 0){
console.log("신고 접수");
reportContainer.style.display = 'none';
messageModalOpen('신고가 접수되었습니다.');
} else {
console.log("신고 실패");
}
},
error: () => {
console.log("신고 오류");
}
});
}
Controller
@Controller
public class ReportController {
@Autowired
private ReportService service;
// ajax 이용하여 신고하기
@PostMapping("/report")
@ResponseBody
public int insertReport(@SessionAttribute(value = "loginMember") Member loginMember,
@RequestParam(value="reportType", required=false) String reportType,
@RequestParam(value="reportTargetNo", required=false, defaultValue="0") int reportTargetNo,
@RequestParam(value="reportReason", required=false) String reportReason,
@RequestParam(value="reportContent", required=false) String reportContent
) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("reportType", reportType);
map.put("reportTargetNo", reportTargetNo);
map.put("reportReason", reportReason);
map.put("reportContent", reportContent);
map.put("memberNo", loginMember.getMemberNo());
int result = 0;
if(loginMember != null) {
result = service.insertReport(map);
}
return result;
}
}
mapper
<insert id="insertReport">
INSERT INTO REPORT VALUES(SEQ_REPORT_NO.NEXTVAL, #{reportType}, #{memberNo}, #{reportTargetNo}, #{reportReason},
DEFAULT, NULL, NULL, #{reportContent})
</insert>
4.2. ajax/axios를 활용하여 비동기로 관리자 페이지 기능 구현
- 필터의 경우, 필터 별로 고유한 아이디를 주어 선택될 때마다 아이디의 값을 컨트롤러로 전달하였고,
- 검색의 경우, 검색어가 입력될 때마다 검색어를 컨트롤러로 전달하였다.
- 필터 아이디의 값과 검색어는 mapper에서 if문을 경우의 수를 구분하여 적용하였다.
- 각각의 결과는 비동기를 이용하여 새로 목록에 조회되도록 하였다.
회원관리 Controller
@Controller
public class AdminController {
@Autowired
private AdminService service;
//..(중략)..
// 전체 회원 조회(정렬, 페이지네이션, 검색)
@GetMapping("/admin/members/list")
@ResponseBody
public String selectMember(@RequestParam(value="cp", required=false, defaultValue="1") int cp,
@RequestParam(value="authFilter", required=false, defaultValue="0") String authFilter,
@RequestParam(value="statFilter", required=false, defaultValue="0") String statFilter,
@RequestParam(value="keyword", required=false) String keyword) {
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("authFilter", authFilter); // 판매자 인증 상태 필터
paramMap.put("statFilter", statFilter); // 계정 상태 필터
if(keyword != null) {
paramMap.put("keyword", keyword); // 검색어
}
Map<String, Object> map = new HashMap<String, Object>();
// 전체 회원 정보 조회 + 페이지네이션 + 정렬
map = service.selectMember(paramMap, cp);
return new Gson().toJson(map);
}
//..(중략)..
}
회원관리 Service
@Service
public class AdminServiceImpl implements AdminService{
@Autowired
private AdminDAO dao;
//..(중략)..
// 전체 회원 조회 (정렬, 페이지네이션, 검색)
@Override
public Map<String, Object> selectMember(Map<String, Object> paramMap, int cp) {
/* 페이지네이션 */
// 1. 전체 개수를 가져옴.
int memberListCount = dao.memberListCount(paramMap);
// 2. 가져온 개수와 현재 페이지를 이용해서 페이지네이션 객체 생성
Pagination pagination = new Pagination(memberListCount, cp, 15);
// 3. 페이네이션 객체를 생성해 목록 불러오기
// 전체 회원 조회(정렬 포함)
List<Admin> memberList = dao.selectMember(paramMap, pagination);
Map<String, Object> map = new HashMap<String, Object>();
map.put("memberListCount", memberListCount);
map.put("pagination", pagination);
map.put("memberList", memberList);
return map;
}
//..(중략)..
}
회원관리 DAO
@Repository
public class AdminDAO {
@Autowired
private SqlSessionTemplate sqlSession;
//..(중략)..
/** 전체 회원 조회(페이지네이션, 정렬 포함)
* @param paramMap
* @param pagination
* @return
*/
public List<Admin> selectMember(Map<String, Object> paramMap, Pagination pagination) {
int offset = (pagination.getCurrentPage() -1) * 15;
RowBounds rowBounds = new RowBounds(offset, 15);
return sqlSession.selectList("adminMapper.selectMemberList", paramMap, rowBounds);
}
//..(중략)..
}
회원관리 mapper
<!-- 전체 회원 정보 조회 (정렬 별로 포함) -->
<select id="selectMemberList" resultMap="admin_rm">
SELECT *
FROM (SELECT
(CASE
WHEN REPORT_TYPE = 'M' THEN 'M'
WHEN REPORT_TYPE IS NULL THEN NULL
ELSE NULL
END)REPORT_TYPE,
RANK() OVER(PARTITION BY REPORT_TYPE, REPORT_TARGET_NO ORDER BY REPORT_NO DESC) AS RANKING,
RANK() OVER(PARTITION BY MEMBER_NO ORDER BY REPORT_TYPE DESC) AS DUPL_FLAG,
MEMBER_NO, REPORT_TARGET_NO,
MEMBER_ID, MEMBER_NAME, MEMBER_NICKNAME, MEMBER_TEL, MEMBER_DEL_FL, SIGNUP_DATE, AUTHORITY, PROFILE_IMG, MEMBER_BIRTH,
REPLACE(MEMBER_ADDRESS, ',,', ' ') MEMBER_ADDRESS, DEFAULT_FL, FARM_IMG, REPORT_NO, REPORT_MEMBER_NO, REPORT_REASON, REPORT_DATE, REPORT_PENALTY,
PROCESS_DATE, REPORT_CONTENT
FROM MEMBER
LEFT JOIN ADDRESS USING(MEMBER_NO)
LEFT JOIN SELLER USING(MEMBER_NO)
LEFT JOIN REPORT ON (MEMBER_NO = REPORT_TARGET_NO)
WHERE MEMBER_ID != 'admin'
AND DEFAULT_FL = 'Y'
ORDER BY MEMBER_NO)
WHERE RANKING = 1 <!--누적 신고 중 제일 최근 값 가져오기 -->
AND DUPL_FLAG = 1 <!--reportTargetNo가 같을 때 신고 타입 'M'인 경우만 가져오기 -->
<if test='authFilter==0 and statFilter==0'> <!--전체 -->
</if>
<if test='authFilter==1'> <!--판매자인증: 미등록 -->
AND AUTHORITY = 0
</if>
<if test='authFilter==2'> <!--판매자인증: 판매자 -->
AND AUTHORITY = 1
</if>
<if test='authFilter==3'> <!--판매자인증: 인증대기 -->
AND AUTHORITY = 3
</if>
<if test='authFilter==4'> <!--판매자인증: 인증보류 -->
AND AUTHORITY = 4
</if>
<if test='statFilter==1'> <!--상태: 활동중 -->
AND MEMBER_DEL_FL = 'N'
AND (REPORT_PENALTY IS NULL
OR REPORT_PENALTY = 'N'
OR REPORT_PENALTY = 'A')
AND REPORT_TYPE = 'M'
</if>
<if test='statFilter==2'> <!--상태: 정지 -->
AND MEMBER_DEL_FL = 'N'
AND REPORT_PENALTY = 'Y'
AND PROCESS_DATE IS NOT NULL
AND REPORT_TYPE = 'M'
</if>
<if test='statFilter==3'> <!--상태: 강제 탈퇴 -->
AND MEMBER_DEL_FL = 'Y'
</if>
<if test='keyword != null'>
AND (LOWER(MEMBER_ID) LIKE LOWER('%${keyword}%')
OR LOWER(MEMBER_NICKNAME) LIKE LOWER('%${keyword}%')
OR MEMBER_NO LIKE ('%${keyword}%'))
</if>
</select>
회원관리 JS (axios)
/** 전체 회원 정보 조회 함수 */
const selectMemberList = (cp) => {
axios.get("/admin/members/list", {
params: { "cp": cp,
"authFilter": authFilter,
"statFilter": statFilter,
"keyword": keyword}
})
.then((response) => {
const map = response.data;
printMemberList(map.memberList, map.pagination);
}).catch(() => {
console.log("회원 정보 조회 실패");
});
}
//..(중략)..
[+]
▶ 판매자 인증 Controller
▶ 신고 내역 관리 Controller
- 신고된 회원 강제 탈퇴, 정지, 반려
- 신고된 게시글, 댓글 삭제, 반려
-
각 대상별로 다르게 처리되어야 했으므로 각각 기능을 다르게 만들었다.
특히 판매자의 경우, 신고된 상태를 변경하는 것에서 그치지 않고
판매자가 쓴 판매글까지 같이 삭제되어야 했기 때문에 한 번 더 처리를 해주었다.
신고 처리 Controller
@Controller
public class AdminProcessController {
@Autowired
private AdminProcessService service;
// 관리자페이지 - 신고 처리
/*
계정 - 강제 탈퇴, 정지, 반려
게시글 - 삭제, 반려
admin-mapper 그대로 사용
*/
// 회원 관리 - 강제 탈퇴 (신고 내역 없어도 가능)
@PatchMapping("/admin/members/{memberNo}/kickout")
@ResponseBody
public int memberKickout(@PathVariable("memberNo") int memberNo) {
return service.memberKickout(memberNo);
}
// 신고 계정 - 강제탈퇴 // 신고된 회원 강제 탈퇴 + REPORT 테이블 변경하기 + 판매자면 판매상품 지우기
@PatchMapping("/report/M/{memberNo}/kickout")
@ResponseBody
public int reportMemberKickout(@PathVariable("memberNo") int memberNo,
@RequestParam(value="authority", required=false, defaultValue="0") int authority) {
return service.reportMemberKickout(memberNo, authority);
}
// 신고 계정 - 정지 // 스케쥴러로 7일 뒤에 풀기
@PatchMapping("/report/M/{memberNo}/suspension")
@ResponseBody
public int reportMemberBanned(@PathVariable("memberNo") int memberNo) {
return service.reportMemberBanned(memberNo);
}
// 신고 계정 - 반려
@PatchMapping("/report/M/{memberNo}/hold")
@ResponseBody
public int reportMemberLeave(@PathVariable("memberNo") int memberNo) {
return service.reportMemberLeave(memberNo);
}
// 신고 게시글(판매글, 커뮤니티 게시글, 커뮤니티 댓글) - 삭제
@PatchMapping("/report/{reportType}/{contentNo}/delete")
@ResponseBody
public int reportDeleteContent(@PathVariable("contentNo") int contentNo,
@PathVariable("reportType") String reportType) {
return service.reportDeleteContent(contentNo, reportType);
}
// 신고 게시글 - 반려
@PatchMapping("/report/{reportType}/{contentNo}/hold")
@ResponseBody
public int reportLeaveContent(@PathVariable("contentNo") int contentNo,
@PathVariable("reportType") String reportType) {
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("contentNo", contentNo);
paramMap.put("reportType", reportType);
return service.reportLeaveContent(paramMap);
}
}
신고 처리 Service
@Service
public class AdminProcessServiceImpl implements AdminProcessService{
@Autowired
private AdminProcessDAO dao;
// 관리자 필터
// 관리자인지 확인
@Override
public int checkAdmin() {
return dao.checkAdmin();
}
// 회원 강제 탈퇴 (회원관리, 신고내역x)
@Override
public int memberKickout(int memberNo) {
return dao.memberKickout(memberNo);
}
// 신고된 회원 강제 탈퇴 (신고내역 O)
@Override
public int reportMemberKickout(int memberNo, int authority) {
int result = 0;
// 강제 탈퇴 시키고
result = dao.memberKickout(memberNo);
// 강제 탈퇴가 성공한다면
if(result > 0) {
// 신고 상태 변경, 신고 처리일자 추가
result = dao.changeReportStatus(memberNo);
// 판매자 강제 탈퇴 시, 판매글 삭제
if(authority == 1) {
result = dao.deletePostofSeller(memberNo);
}
}
return result;
}
// 신고된 회원 계정 정지
@Override
public int reportMemberBanned(int memberNo) {
return dao.reportMemberBanned(memberNo);
}
// 신고 계정 - 반려
@Override
public int reportMemberLeave(int memberNo) {
return dao.reportMemberLeave(memberNo);
}
// 신고 게시글 - 삭제
@Override
public int reportDeleteContent(int contentNo, String reportType) {
int result = 0;
// 커뮤니티 게시글 삭제
if(reportType.equals("B")) {
result = dao.reportDeleteBoard(contentNo);
// 판매글 삭제
} else if(reportType.equals("P")) {
result = dao.reportDeletePost(contentNo);
// 댓글
} else if(reportType.equals("C")) {
result = dao.reportDeleteComment(contentNo);
}
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("contentNo", contentNo);
paramMap.put("reportType", reportType);
// 삭제 후 신고 상태 변경, 처리 일자 추가
if(result > 0) {
result = dao.changeReportStatusCt(paramMap);
}
return result;
}
// 신고 게시글 - 반려
@Override
public int reportLeaveContent(Map<String, Object> paramMap) {
return dao.reportLeaveContent(paramMap);
}
//-----------------------------------------------
// 정지된 계정 리스트 불러오기 (스케쥴링)
@Override
public List<Admin> selectBannedAccountList() {
return dao.selectBannedAccountList();
}
// 정지된 계정 활성화 (스케쥴링)
@Override
public int activateAccount(int targetNo) {
return dao.activateAccount(targetNo);
}
}
▶신고 대상 처리 DAO
▶신고 대상 처리 mapper
4.3. @Scheduled를 활용하여 정지 계정 자동 활성화
- 회원이 신고 당했을 경우, 계정을 7일 간 정지 처리할 수 있다.
- @Scheduled를 활용하여, 계정이 정지된 일자가 정지된 일자의 7일을 넘었을 경우,
자동으로 활성화되도록 하였다.
4.4. Chart.js를 활용한 관리자 대시보드 그래프 구현
5.1. Oracle Cloud 호스팅 중 예외 발생
- Oracle Cloud FarmFarm 프로젝트 파일을 호스팅하는 도중
- 관리자페이지 대시보드의 그래프가 나오지 않은 상황이 발생하였다.
- 로컬에서 서버를 돌렸을 경우에는 문제 없이 진행되었기 때문에 팀원 모두 원인을 찾지 못하는 상황에서
- 원인은 Chart.js를 사용하여 구현한 가입, 주문 수의 SQL문의 WHERE절인 것을 발견하였다.
기존 코드
<select id="selectOrderGraph" resultMap="graph_rm">
SELECT TO_CHAR(b.OD, 'MM-DD') AS ORDER_DATE
, NVL(SUM(a.cnt), 0) AS ORDER_COUNT
FROM ( SELECT TO_CHAR(ORDER_DATE, 'YYYY-MM-DD') AS ORDER_DATE
,COUNT(*) cnt
FROM "ORDER"
WHERE ORDER_DATE BETWEEN SYSDATE-31
AND SYSDATE
GROUP BY ORDER_DATE
) a
, (SELECT (TO_DATE(SYSDATE-30,'YY-MM-DD') + LEVEL) AS OD
FROM dual
<![CDATA[CONNECT BY LEVEL <= 31]]>) b
WHERE b.OD = a.ORDER_DATE(+)
GROUP BY b.OD
ORDER BY b.OD
</select>
- 기존 코드의 WHERE절을 보면 CHAR 타입 데이터와 DATE 타입 데이터를 형변환 없이 비교하고 있다는 것을 알 수 있다.
- 로컬 서버 환경에서는 타입이 다른 날짜 데이터의 비교가 가능했지만, Linux 환경에서 Oracle Cloud에 호스팅 된 페이지에서는 두 데이터의 타입이 달라 비교가 어려웠다.
- 타입을 수정하는 것으로 문제를 해결하지 않고, 팀원들과 같이 고민하여 아래와 같이 SQL문을 개선할 수 있었다.
개선된 코드
<select id="selectOrderGraph" resultMap="graph_rm">
<![CDATA[
SELECT ORDER_DATE,
(SELECT COUNT(*)
FROM "ORDER" o
WHERE TO_CHAR(o.ORDER_DATE , 'YYYY-MM-DD') = a.ORDER_DATE) ORDER_COUNT
FROM (SELECT TO_CHAR(SYSDATE - 31 + LEVEL, 'YYYY-MM-DD') ORDER_DATE
FROM DUAL CONNECT BY LEVEL <=31) a]]>
</select>
5.2. RESTFUL API로 리팩토링 진행
- 기존에는 POST/GET mapping 두 가지만 사용하였다.
- 이러다보니 각 요청의 동작을 명확히 하는데 한계가 있었다.
기존 코드
// 신고 게시글(판매글, 커뮤니티 게시글, 커뮤니티 댓글) - 삭제
@GetMapping("/report/deleteContent")
@ResponseBody
public int reportDeleteContent(int hiddenContentNo, String reportType) {
return service.reportDeleteContent(hiddenContentNo, reportType);
}
- 예를 들어, 게시글, 댓글 등을 삭제하는 코드의 경우
기존의 코드는 삭제되는 주체를 알아보기 힘들고 어떤 동작을 진행했는지 직관적으로 알아보기 어려웠다. - 이에 매핑 주소에 신고 대상의 타입(reportType)과 신고 대상의 식별 번호(contentNo)을 받아와 알려 주고,
- PostMapping을 PatchMapping으로 바꾸어 일부 수정한다는 것을 알리도록 하였다.
개선된 코드
// 신고 게시글(판매글, 커뮤니티 게시글, 커뮤니티 댓글) - 삭제
@PatchMapping("/report/{reportType}/{contentNo}/delete")
@ResponseBody
public int reportDeleteContent(@PathVariable("contentNo") int contentNo,
@PathVariable("reportType") String reportType) {
return service.reportDeleteContent(contentNo, reportType);
}
5.3. 반복되는 코드 개선
- 기존에는 조건에 차이가 있으면, if문으로 일일이 분리하여 작성하였다.
- 그러나 이와 같은 경우, 조건에만 차이가 존재하고 비슷한 코드가 반복되는 상황이 발생하였다.
기존 코드
reportBtn.addEventListener("click", () => {
// 판매자 신고
if(pathname == "seller") {
if(reportTargetNo == 0){
messageModalOpen("관리자는 신고 대상이 아닙니다.");
} else {
// 신고 모달 열리기
openReportModal();
reportType = "M";
reportTargetNo = targetNo;
}
}
// 채팅방 회원 신고(판매자, 일반회원 모두 신고 가능, authority로 구분)
if(pathname == "chat") {
if(reportTargetNo == 0){
messageModalOpen("관리자는 신고 대상이 아닙니다.");
} else {
// 신고 모달 열리기
openReportModal();
reportType = "M";
reportTargetNo = selectedChatNo; //chatContext.js에서 선언한 변수
}
}
// 판매 게시글 신고 (사고팔고)
if(pathname == "post"){
if(reportTargetNo == 0){
messageModalOpen("관리자는 신고 대상이 아닙니다.");
} else {
// 신고 모달 열리기
openReportModal();
reportType = "P";
reportTargetNo = targetNo; //postNo
}
}
});
- 공통된 구문을 하나로 묶는 것이 효율적이라는 생각이 들었다.
- messageModalOpen()함수와 openReportModal() 함수가 작동되는 조건이 동일하기 때문에
- 먼저 두 함수가 작동되는 조건을 하나로 묶고
- 세부 조건을 switch문을 이용하여 pathname에 따라 결과를 다르게 하였다.
개선된 코드
reportBtn.addEventListener("click", () => {
if(reportTargetNo == 0){
messageModalOpen("관리자는 신고 대상이 아닙니다.");
} else{
openReportModal();
switch(pathname){
case 'seller': reportType = 'M'; reportTargetNo = targetNo; break;
case 'post': reportType = 'P'; reportTargetNo = targetNo; break;
case 'chat': reportType = 'M'; reportTargetNo = selectedChatNo; break;
}
}
}