95 lines
3.0 KiB
JavaScript
95 lines
3.0 KiB
JavaScript
import { useState, useCallback } from "react";
|
|
|
|
const useTermsStateMachine = (initialState) => {
|
|
const [isTransitioning, setIsTransitioning] = useState(false);
|
|
const [state, setState] = useState({
|
|
termsChecked: false,
|
|
privacyChecked: false,
|
|
optionalChecked: false,
|
|
selectAllChecked: false,
|
|
error: null, // 1. 에러 상태 추가
|
|
...initialState,
|
|
});
|
|
|
|
const updateStateAsync = useCallback(
|
|
async (updates) => {
|
|
if (isTransitioning) {
|
|
const err = new Error("State transition already in progress.");
|
|
if (process.env.NODE_ENV === "development") {
|
|
console.warn("[useTermsStateMachine] Rejected:", err.message);
|
|
}
|
|
// 2. 에러 상태를 설정하고 throw
|
|
setState((s) => ({ ...s, error: err }));
|
|
throw err;
|
|
}
|
|
|
|
setIsTransitioning(true);
|
|
// 3. 이전 에러 상태 초기화
|
|
setState((s) => ({ ...s, error: null }));
|
|
|
|
try {
|
|
const newState = await new Promise((resolve) => {
|
|
setState((currentState) => {
|
|
const nextState = { ...currentState, ...updates };
|
|
|
|
const {
|
|
termsChecked: currentTerms,
|
|
privacyChecked: currentPrivacy,
|
|
optionalChecked: currentOptional,
|
|
} = currentState;
|
|
|
|
const termsChecked =
|
|
"termsChecked" in updates
|
|
? updates.termsChecked
|
|
: currentTerms;
|
|
const privacyChecked =
|
|
"privacyChecked" in updates
|
|
? updates.privacyChecked
|
|
: currentPrivacy;
|
|
const optionalChecked =
|
|
"optionalChecked" in updates
|
|
? updates.optionalChecked
|
|
: currentOptional;
|
|
|
|
if (
|
|
"termsChecked" in updates ||
|
|
"privacyChecked" in updates ||
|
|
"optionalChecked" in updates
|
|
) {
|
|
nextState.selectAllChecked =
|
|
termsChecked && privacyChecked && optionalChecked;
|
|
} else if ("selectAllChecked" in updates) {
|
|
nextState.termsChecked = updates.selectAllChecked;
|
|
nextState.privacyChecked = updates.selectAllChecked;
|
|
nextState.optionalChecked = updates.selectAllChecked;
|
|
}
|
|
|
|
if (process.env.NODE_ENV === "development") {
|
|
console.log(
|
|
"[useTermsStateMachine] State transition:",
|
|
currentState,
|
|
"->",
|
|
nextState
|
|
);
|
|
}
|
|
resolve(nextState);
|
|
return nextState;
|
|
});
|
|
});
|
|
setIsTransitioning(false);
|
|
return newState;
|
|
} catch (error) {
|
|
setIsTransitioning(false);
|
|
console.error("[useTermsStateMachine] State update failed:", error);
|
|
// 4. 에러 상태를 설정하고 다시 throw
|
|
setState((s) => ({ ...s, error }));
|
|
throw error;
|
|
}
|
|
},
|
|
[isTransitioning]
|
|
);
|
|
|
|
return { state, updateStateAsync };
|
|
};
|
|
|
|
export default useTermsStateMachine;
|