Loading the catalog…
Loading the catalog…
이제 메일 발송 쪽은 어느 정도 연결됐다. 근데 수신자를 관리하려면 아직 문제가 하나 남아 있었다. 등록도 조회도 비활성화도 전부 API로 해야 했다. 개발할 때는 API만 있어도 확인할 수 있지만 실제로 업무에서 쓰려면 이건 좀 불편했다. 그래서 이번에는 알림 수신자를 관리할 수 있는 화면을 따로 만들었다. 어디에서 관리하게 할까? 처음에는 외부 중요공지 화면 안에 수신자 관리를 같이 넣을까도 생각했다. 근데 공지를 확인하는 기능이랑 알림 받을 사람을 관리하는 기능은 성격이 조금 달랐다. 공지 화면에 다 넣으면 점점 복잡해질 것 같았다. 그래서 아예 메뉴를 하나 분리했다. <a class="app-nav-link" href="/notifications/"> 알림 관리 </a> 기존 메뉴도 홈 입찰공고 외부 중요공지 알림 관리 이렇게 네 개가 됐다. /notifications 로 들어가면 알림 관리 화면이 열리도록 연결했다. @GetMapping({"/notifications", "/notifications/"}) public String notificationSubscriberPage() { return "forward:/notifications/index.html"; } 화면에 뭘 보여줘야 하지? 수신자 목록만 보여주는 건 조금 부족해 보였다. 관리할 때는 지금 몇 명이 등록돼 있고 그중 실제로 알림을 받는 사람이 몇 명인지 바로 보고 싶었다. 그래서 상단에 전체 신청자 수 활성 신청자 수 비활성 신청자 수 를 먼저 보여주고 아래에는 신청자 목록을 배치했다. 목록에서는 이름 이메일 알림 유형 상태 등록일 관리 를 확인할 수 있게 했다. 전체 신청자와 활성 / 비활성 상태를 한 화면에서 확인할 수 있게 했다 등록은 모달로 만들었다 신청자를 추가할 때 다른 페이지로 이동하게 할 필요는 없다고 생각했다. 관리 화면에서 바로 등록하고 등록이 끝나면 다시 목록을 확인하는 흐름이 더 자연스러웠다. 그래서 + 신청자 등록 버튼을 누르면 모달이 열리도록 만들었다. 입력하는 값도 많지 않다. 이름 이메일 알림 유형 지금은 알림 유형이 PIA 중요공지 하나뿐이지만 기존에 만들어둔 notificationType 을 그대로 사용했다. 등록하면 앞에서 만든 API를 호출한다. await requestJson(API_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: elements.name.value.trim(), email: elements.email.value.trim(), notificationType: elements.notificationType.value }) }); 등록이 끝나면 모달을 닫고 목록을 다시 불러오게 했다. closeModal(); showToast("신청자를 등록했습니다."); await loadSubscribers(); 따로 새로고침하지 않아도 바로 등록 결과를 확인할 수 있다. 이미 등록된 이메일이면? 화면을 만들면서 정상적인 경우만 생각하면 안 됐다. 이미 등록된 이메일을 또 입력할 수도 있다. 23편에서 백엔드에서는 중복 등록을 막아놨다. 이번에는 그 결과를 화면에서도 알아볼 수 있게 했다. function registrationErrorMessage(error) { if (error instanceof ApiError && error.status === 409) { return "이미 등록된 이메일입니다."; } if (error instanceof ApiError && error.status === 400) { return error.message || "입력값을 확인해주세요."; } return "신청자를 등록하지 못했습니다. 잠시 후 다시 시도해주세요."; } 백엔드에서 409가 오면 사용자에게 그냥 오류라고 보여주는 게 아니라 이미 등록된 이메일입니다. 라고 알려준다. 이메일 형식이 잘못된 경우도 등록 요청을 보내기 전에 한 번 확인하도록 했다. 삭제보다 비활성화 수신자를 관리할 때 삭제 버튼을 만들 수도 있었다. 근데 앞에서 DB 구조를 만들 때부터 수신자를 삭제하지 않고 비활성화하기로 했다. 발송 대상에서는 제외하되 등록했던 정보는 남겨두기 위해서였다. 그래서 화면에서도 삭제 대신 비활성화 버튼을 만들었다. await requestJson( `${API_URL}/${encodeURIComponent(subscriber.id)}/disable`, { method: "PATCH" } ); 비활성화하기 전에 한 번 더 확인하도록 했다. if (!window.confirm( `${targetName} 신청자를 비활성화하시겠습니까?` )) { return; } 처리가 끝나면 목록을 다시 불러오고 상태도 바로 비활성 으로 바뀐다. API로만 가능했던 수신자 관리를 화면에서 처리할 수 있게 됐다 모바일에서는 표가 좀 애매했다 데스크톱에서는 표가 보기 편했다. 근데 모바일에서 이름과 이메일 알림 유형과 등록일까지 전부 표에 넣으니까 공간이 부족했다. 표를 억지로 줄이는 것보다 모바일에서는 카드 형태가 낫겠다고 생각했다. 그래서 화면 크기에 따라 데스크톱 → 테이블 모바일 → 카드 목록 으로 다르게 보여주도록 했다. 390px 화면에서도 가로 스크롤이 생기지 않는지 확인하는 테스트도 추가했다. 화면도 실제 동작까지 확인했다 화면만 그려놓고 끝내지는 않았다. Playwright 테스트에서 목록 조회 신규 수신자 등록 수신자 비활성화 중복 이메일 안내 신청자가 없을 때 빈 화면 모바일 카드 화면 을 확인하도록 했다. 특히 등록 후 전체 신청자 수가 바뀌는지 비활성화 후 상태가 실제로 변경되는지도 같이 확인했다. 이제 23편에서 만든 API를 직접 호출하지 않아도 알림 관리 화면 ↓ 신청자 등록 ↓ 활성 / 비활성 상태 확인 ↓ 필요하면 비활성화 이 흐름으로 관리할 수 있게 됐다. 처음에는 메일 한 통 보내는 기능에서 시작했는데 이제는 누가 알림을 받을지도 화면에서 관리할 수 있게 됐다.
What RADAR observed and classified to build this opportunity. It is what the source published, not a verification that the offer is still active.
이제 알림 받을 사람도 화면에서 관리하자. 이제 메일 발송 쪽은 어느 정도 연결됐다. 근데 수신자를 관리하려면 아직 문제가 하나 남아 있었다. 등록도 조회도 비활성화도 전부 API로 해야 했다. 개발할 때는 API만 있어도 확인할 수 있지만 실제로 업무에서 쓰려면 이건 좀 불편했다. 그래서 이번에는 알림 수신자를 관리할 수 있는 화면을 따로 만들었다. 어디에서 관리하게 할까? 처음에는 외부 중요공지 화면 안에 수신자 관리를 같이 넣을까도 생각했다. 근데 공지를 확인하는 기능이랑 알림 받을 사람을 관리하는 기능은 성격이 조금 달랐다. 공지 화면에 다 넣으면 점점 복잡해질 것 같았다. 그래서 아예 메뉴를 하나 분리했다. 알림 관리 기존 메뉴도 홈 입찰공고 외부 중요공지 알림 관리 이렇게 네 개가 됐다.…
Open source