최근에 정기구독 서비스를 만들어 배포했다. 신청할 서비스, 주기와 요일을 선택하면 따로 신청하지 않아도 정기적으로 서비스를 이용할 수 있다. 서비스에 대한 결제는 해당 정기구독의 마지막 서비스가 완료되면 자동으로 결제된다. 다음 화면은 청소 서비스를 진행해주시는 매니저님 분들이 사용하는 앱이다.
서비스 종료 촬영까지 마친 후 끝! → 알림 보내기까지 완료되면 서비스가 완료된다.


아래 사진에서 보낼게요! 버튼을 클릭하면 서버로 자동 결제 요청을 보내는데 저 버튼을 빠르게 연속해서 누르면 결제 또한 여러 번 이루어졌다… 중복 결제를 방지하고자 once라는 유틸 함수를 만들어 적용해보았다.
export const once = (fn: Function) => {
let isDone = false;
return (...args: any[]) => {
if (!isDone) {
isDone = true;
fn(...args);
}
};
};
타입스크립트에서 any 타입은 최대한 사용하지 않는 것이 좋지만 어느 곳에서 어떻게 사용될 지 모르는 util 함수이기에 어쩔 수 없이 사용했다..
우선 보낼게요! 버튼 클릭시 호출되는 함수는 다음과 같았다.
const checkDoneEnd = () => {
// console.log('checkDoneEnd!!');
onchangestate(5);
setOpenEnd(false);
};
현재 서비스의 진행 상태를 나타내는 값을 변경해주고 모달을 닫아주는게 끝이다. state가 5로 변경되면 서비스가 완료된 것이며, 각 서비스들의 상태를 done으로 변경 후 서버와 고객앱으로 sync emit을 보내고 고객에게 서비스 종료 알림을 보낸다.
정기구독 자동 결제 요청을 보내는 함수 completeService()를 만들과 다음과 같이 수정했다.
// 정기구독 서비스 자동결제 요청 함수
const completeService = async () => {
const { bsids, visitdt, custaddr } = billservices;
try {
const result = await Store.sendPost(`${SERVER_PAGE}/standingpay`, {
billServiceIds: bsids?.split(',').map((id) => NUmber(id) || [],
visitdt,
custaddr,
});
if (result)
addChatMsg(6, billservice.custid);
onchangestate(5);
} catch (error) {
console.error(error);
const { message } = error as unknown as AxiosError; // ***
setErrorMessage(message);
setErrorStanding(true);
}
};
// 서비스 끝 (문닫힘) + 정기구독 서비스 자동결제
const checkDoneEnd = useCallback(
once(() => {
// onchangestate(5);
setOpenEnd(false);
completeService();
}),
[setOpenEnd, completeService]
);
useCallback과 once 함수를 같이 사용하여 ‘보낼게요!’버튼을 빠르게 연속 클릭하여도 결제 요청은 단 한 번만 보내도록 수정했다.
사실 여기서 더 중요한 것은 *** 표시가 있는 부분이다. 혹시 결제 진행이 정상적으로 이루어지지 않은 경우 매니저님분들이 확인하고 사무실로 연락을 줄 수 있도록 메시지를 띄워줘야 하는데 타입 에러가 나서 어서션을 통해 타입을 좁히는 방법을 선택했었다.
동료 개발자님과 cto 본부장님과 타입스크립트 스터디를 계획중인데 시작 전에 책 한권을 1독하면서 알게된 내용은 일단 저 방법은 절대 권장하지 않는 방법이었다.
우선 에러의 원인은 에러의 타입은 실제로 알 수 없기 때문에 any 혹은 unknown이다. 왜나면 throw로 에러를 던질 때 에러 객체 뿐만 아니라 다른 어떤 값도 던질 수 있기 때문이다.
throw 'Error';
마침 해당 내용을 다루는 챕터의 발표자가 나여서 발표와 동시에 이 코드를 보고 수정하고 새로 업로드를 할 계획이다.