제출 버튼 검증 및 중복 제출 방지 - #4
Conversation
모든 제출 핸들러가 비동기인데 진행 중 재실행을 막는 장치가 없어, 저장 버튼을 연타하면 문서가 여러 번 생성될 수 있었습니다. 잠금 상태를 ref로 관리해 상태 반영 전의 연속 호출까지 차단하는 공용 훅을 추가했습니다. 진행 여부를 isSubmitting으로 노출해 버튼 비활성화에 함께 사용합니다.
루틴 저장 시 제목 없음, 반복 요일 미선택, 변경 적용 날짜 없음, 종료 날짜 없음, 종료 날짜가 시작 날짜보다 빠름 등 다섯 가지 실패 조건이 모두 조용한 early return이었습니다. 버튼은 활성인데 눌러도 아무 일이 없고 사유도 알 수 없어, 사용자가 무엇을 고쳐야 하는지 판단할 수 없었습니다. 검증 로직을 getRoutineValidationMessage로 분리하고 첫 번째 실패 사유 하나만 toast로 안내하도록 했습니다. 변경 사항이 없으면 저장 버튼을 비활성화하고, 제출 중에도 비활성화해 중복 저장을 막았습니다.
할 일 저장 시 제목 없음과 카테고리 없음이 조용한 early return이었습니다. 특히 카테고리가 하나도 없으면 카테고리 선택 필드는 잠기는데 완료 버튼은 눌려서, 신규 사용자가 빠져나갈 수 없는 상태가 됐습니다. 실패 사유를 toast로 안내하고, 카테고리가 없을 때는 먼저 추가하도록 유도합니다. 변경 사항이 없거나 제출 중이면 저장 버튼을 비활성화합니다.
카테고리명이 비어 있을 때 저장이 조용히 무시되던 문제를 toast 안내로 바꿨습니다. 이름과 색상 모두 변경되지 않았거나 제출 중이면 저장 버튼을 비활성화합니다.
공지 제목이 비어 있을 때 저장이 조용히 무시되던 문제를 toast 안내로 바꿨습니다. 저장 실패 시 사용자에게 알리도록 예외 처리를 추가하고, 변경 사항이 없거나 제출 중이면 저장 버튼을 비활성화합니다.
시작 날짜와 변경 적용 날짜의 기본값을 toISOString으로 만들고 있어 UTC 기준으로 해석됐습니다. KST 자정부터 오전 9시 사이에 루틴을 추가하면 시작 날짜가 어제로 잡히고, 그대로 저장되면 어제 날짜에 미완료 루틴이 생겨 월간 통계까지 어긋났습니다. 같은 모듈의 getTodayLocalDate 헬퍼를 사용하도록 변경했습니다.
|
@codex review 한국어로 코드 리뷰를 진행해주세요. 다음 기준을 우선적으로 검토해주세요.
단순 스타일 취향은 제외하고, 실제로 수정이 필요한 경우에는 수정 예시 코드도 함께 제안해주세요. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5175ddad21
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
확인 버튼에 비활성 처리가 없고 onConfirm이 끝나야 모달이 닫히는 구조라, 처리 중에도 버튼이 계속 눌렸습니다. 회원탈퇴는 구글 재인증 팝업을 기다리는 구간이 있어 그동안 탈퇴가 여러 번 시작될 수 있었고, 나중 호출이 이미 삭제된 유저에 접근해 실패하면서 탈퇴가 성공했는데도 실패 안내가 뜨는 상황이 발생했습니다. onConfirm의 Promise가 끝날 때까지 확인, 취소, 배경 클릭을 모두 잠그도록 했습니다. 호출부 수정 없이 공용 컴포넌트에서 처리해 같은 모달을 쓰는 할 일 일괄 삭제에도 동일하게 적용됩니다.
저장이 끝난 뒤 통계 재생성이나 목록 갱신에서 오류가 나면 하나의 catch가 저장 실패로 안내하고 모달을 그대로 유지했습니다. 안내대로 다시 저장하면 이미 생성된 문서가 한 번 더 만들어져 중복 문서와 잘못된 통계가 생길 수 있었습니다. 쓰기 성공 여부를 별도로 추적해, 갱신 단계에서 실패하면 모달을 닫고 새로고침을 안내하도록 분리했습니다.
변경 감지는 trim된 제목으로 비교하는데 저장은 원문을 그대로 보내고 있어, 공백만 추가한 입력이 버튼으로는 막히고 Enter로는 저장되는 불일치가 있었습니다. 기존 데이터에 앞뒤 공백이 있으면 아무것도 수정하지 않아도 항상 변경으로 감지되는 문제도 있었습니다. 제목을 한 번만 정규화해 변경 감지와 저장 payload가 같은 값을 쓰도록 했습니다. 변경 여부 확인이 저장 버튼 비활성화에만 걸려 있어 Enter로는 우회되던 문제도 핸들러에서 함께 확인하도록 보완했습니다.
|
두 건 모두 유효한 지적이라 반영했습니다. (548b5c4, fc11a92) 1번은 persisted 플래그로 쓰기 성공 시점을 추적해, 갱신 단계 실패 시 모달을 닫고 새로고침을 안내하도록 분리했습니다. 다만 제안하신 onClose() 선행 방식 대신 성공 경로의 순서는 유지했습니다. 정상적인 경우에도 갱신 전에 모달이 닫혀 목록이 잠시 옛 데이터를 보이는 문제가 새로 생기기 때문입니다. 같은 구조인 공지 모달에도 함께 적용했습니다. 2번은 제목 정규화를 일원화했고, 확인 과정에서 더 근본적인 문제를 발견했습니다. 변경 감지가 저장 버튼 비활성화에만 걸려 있어 Enter 제출은 통째로 우회하고 있었습니다. 정규화와 함께 핸들러에서도 변경 여부를 확인하도록 보완했습니다. resolve 부탁드립니다. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fc11a9291f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| // 변경 사항이 없으면 저장 버튼을 비활성화하기 위한 판단값 | ||
| const isDirty = task | ||
| ? trimmedTitle !== task.title || |
There was a problem hiding this comment.
배경
if (!title.trim()) return;형태의 조용한 early return이라 사용자는 무엇을 고쳐야 하는지 알 방법이 없었습니다.동작 규칙
세 가지 상태를 구분했습니다.
설명이 필요한 경우에만 버튼을 활성으로 두어, toast가 뜰 수 있는 경로를 확보했습니다.
변경 사항
검증 사유 안내
실패 사유를 조용히 무시하지 않고 toast로 안내합니다. 사유가 여러 개인 경우 우선순위 순으로 검사해 하나만 표시하고,
toastId로 연타 시 중복 누적을 막았습니다.getRoutineValidationMessage로 분리변경 없음 감지
수정 모드에서 아무것도 바꾸지 않으면 저장 버튼을 비활성화합니다.
불필요한 Firestore 쓰기와 그에 따른 캐시 무효화·리페치가 사라집니다.
중복 제출 방지
useSubmitLock훅을 추가해 4개 모달에 적용했습니다.잠금을 state가 아닌 ref로 관리해, 리렌더 이전의 빠른 연타까지 차단합니다.
기존에는 저장 버튼 연타 시
addDoc이 여러 번 호출되어 문서가 실제로 중복 생성될 수 있었습니다.버그 수정
루틴 기본 날짜가 하루 밀리는 문제
시작 날짜와 변경 적용 날짜의 기본값을
toISOString()으로 만들고 있어 UTC 기준으로 해석됐습니다.KST 자정~오전 9시에 루틴을 추가하면 시작 날짜가 어제로 잡히고, 그대로 저장되면 어제 날짜에 미완료 루틴이 생겨 월간 통계까지 어긋났습니다.
매달 1일 새벽이면 전월 통계에도 영향을 줍니다.
로컬 기준
getTodayLocalDate헬퍼로 교체했으며, 이로써 프로젝트에서 해당 패턴이 모두 제거됐습니다.저장 실패가 알려지지 않던 문제
네 모달 모두
catch에서console.error만 하고 끝나, 네트워크 오류로 저장이 실패해도 사용자는 성공한 것으로 인지했습니다. 실패 toast를 추가했습니다.확인 모달의 중복 실행 (PR #3 리뷰 반영)
확인 버튼에 비활성 처리가 없고
onConfirm이 끝나야 모달이 닫히는 구조라 처리 중에도 버튼이 계속 눌렸습니다. 회원탈퇴는 구글 재인증 팝업을 기다리는 구간이 있어 그동안 탈퇴가 여러 번 시작될 수 있었고, 나중 호출이 이미 삭제된 유저에 접근해 실패하면서 탈퇴가 성공했는데도 실패 안내가 뜨는 상황이 발생했습니다.ConfirmModal이onConfirm의 Promise를 추적해 확인·취소·배경 클릭을 모두 잠그도록 했습니다.공용 컴포넌트에서 처리해, 같은 모달을 쓰는 할 일 일괄 삭제 두 곳에도 함께 적용됩니다.