[251018] fix: EnergyLabel
🕐 커밋 시간: 2025. 10. 18. 23:31:25 📊 변경 통계: • 총 파일: 7개 • 추가: +387줄 • 삭제: -93줄 📁 추가된 파일: + com.twin.app.shoptime/assets/mock/EnergyLabelSample.pdf 📝 수정된 파일: ~ com.twin.app.shoptime/src/actions/actionTypes.js ~ com.twin.app.shoptime/src/actions/convertActions.js ~ com.twin.app.shoptime/src/api/TAxios.js ~ com.twin.app.shoptime/src/components/TItemCard/TItemCard.module.less ~ com.twin.app.shoptime/src/components/TItemCard/TItemCard.new.jsx ~ com.twin.app.shoptime/src/reducers/convertReducer.js 🔧 함수 변경 내용: 📄 com.twin.app.shoptime/src/components/TItemCard/TItemCard.new.jsx (javascript): ✅ Added: hashCode() 🔧 주요 변경 내용: • 타입 시스템 안정성 강화 • 핵심 비즈니스 로직 개선 • API 서비스 레이어 개선 • UI 컴포넌트 아키텍처 개선
This commit is contained in:
@@ -14,31 +14,22 @@ import {
|
||||
setSystemTermination,
|
||||
showError,
|
||||
} from '../actions/commonActions';
|
||||
import {
|
||||
getAuthenticationCode,
|
||||
getReAuthenticationCode,
|
||||
} from '../actions/deviceActions';
|
||||
import {
|
||||
pushPanel,
|
||||
resetPanels,
|
||||
} from '../actions/panelActions';
|
||||
import { getAuthenticationCode, getReAuthenticationCode } from '../actions/deviceActions';
|
||||
import { pushPanel, resetPanels } from '../actions/panelActions';
|
||||
import * as Config from '../utils/Config';
|
||||
import { ACTIVE_POPUP } from '../utils/Config';
|
||||
import * as HelperMethods from '../utils/helperMethods';
|
||||
import {
|
||||
getUrl,
|
||||
URLS,
|
||||
} from './apiConfig';
|
||||
import { getUrl, URLS } from './apiConfig';
|
||||
|
||||
let tokenRefreshing = false;
|
||||
const axiosQueue = [];
|
||||
|
||||
export const setTokenRefreshing = (value) => {
|
||||
console.log("TAxios setTokenRefreshing ", value);
|
||||
console.log('TAxios setTokenRefreshing ', value);
|
||||
tokenRefreshing = value;
|
||||
};
|
||||
export const runDelayedAction = (dispatch, getState) => {
|
||||
console.log("runDelayedAction axiosQueue size", axiosQueue.length);
|
||||
console.log('runDelayedAction axiosQueue size', axiosQueue.length);
|
||||
while (axiosQueue.length > 0) {
|
||||
const requestConfig = axiosQueue.shift(); // queue에서 요청을 하나씩 shift
|
||||
TAxios(
|
||||
@@ -49,7 +40,9 @@ export const runDelayedAction = (dispatch, getState) => {
|
||||
requestConfig.urlParams,
|
||||
requestConfig.params,
|
||||
requestConfig.onSuccess,
|
||||
requestConfig.onFail
|
||||
requestConfig.onFail,
|
||||
false, // noTokenRefresh
|
||||
requestConfig.responseType // ⭐ responseType 전달
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -62,23 +55,24 @@ export const TAxios = (
|
||||
params = {},
|
||||
onSuccess,
|
||||
onFail,
|
||||
noTokenRefresh = false
|
||||
noTokenRefresh = false,
|
||||
responseType = undefined // ⭐ 선택적 파라미터 추가 (기존 코드 영향 없음)
|
||||
) => {
|
||||
const pushQueue = () => {
|
||||
if (!noTokenRefresh) {
|
||||
axiosQueue.push({ type, baseUrl, urlParams, params, onSuccess, onFail });
|
||||
axiosQueue.push({ type, baseUrl, urlParams, params, onSuccess, onFail, responseType });
|
||||
}
|
||||
};
|
||||
|
||||
const decodeMessage = (apiSysMessage) => {
|
||||
try {
|
||||
const decodedBase64 = atob(apiSysMessage);
|
||||
const decodedText = new TextDecoder("utf-8").decode(
|
||||
new Uint8Array(decodedBase64.split("").map((c) => c.charCodeAt(0)))
|
||||
const decodedText = new TextDecoder('utf-8').decode(
|
||||
new Uint8Array(decodedBase64.split('').map((c) => c.charCodeAt(0)))
|
||||
);
|
||||
return decodedText;
|
||||
} catch (error) {
|
||||
console.error("Decoding error:", error);
|
||||
console.error('Decoding error:', error);
|
||||
return apiSysMessage;
|
||||
}
|
||||
};
|
||||
@@ -90,31 +84,34 @@ export const TAxios = (
|
||||
const AUTHORIZATION = { headers: { ...httpHeader } };
|
||||
|
||||
if (accessToken) {
|
||||
AUTHORIZATION.headers["lgsp_auth"] = accessToken;
|
||||
AUTHORIZATION.headers['lgsp_auth'] = accessToken;
|
||||
}
|
||||
AUTHORIZATION.headers["dvc_id"] = deviceId;
|
||||
AUTHORIZATION.headers["refresh_token"] = refreshToken;
|
||||
AUTHORIZATION.headers['dvc_id'] = deviceId;
|
||||
AUTHORIZATION.headers['refresh_token'] = refreshToken;
|
||||
|
||||
if (typeof window === "object") {
|
||||
let url = Array.isArray(baseUrl)
|
||||
? getUrl(getState, baseUrl[0])
|
||||
: getUrl(getState, baseUrl);
|
||||
// ⭐ responseType 옵션 추가 (이미지, PDF 등 바이너리 데이터용)
|
||||
if (responseType) {
|
||||
AUTHORIZATION.responseType = responseType;
|
||||
}
|
||||
|
||||
if (typeof window === 'object') {
|
||||
let url = Array.isArray(baseUrl) ? getUrl(getState, baseUrl[0]) : getUrl(getState, baseUrl);
|
||||
|
||||
if (!url) {
|
||||
//todo error page
|
||||
return;
|
||||
}
|
||||
if (type === "get") {
|
||||
if (type === 'get') {
|
||||
const _urlparams = HelperMethods.createQueryString(urlParams);
|
||||
url += _urlparams ? `?${_urlparams}` : "";
|
||||
url += _urlparams ? `?${_urlparams}` : '';
|
||||
}
|
||||
|
||||
let axiosInstance;
|
||||
switch (type) {
|
||||
case "get":
|
||||
case 'get':
|
||||
axiosInstance = axios.get(url, AUTHORIZATION);
|
||||
break;
|
||||
case "post":
|
||||
case 'post':
|
||||
axiosInstance = axios.post(url, params, AUTHORIZATION);
|
||||
break;
|
||||
// TODO: 다른 HTTP 메소드 있다면 처리 (chw)
|
||||
@@ -123,18 +120,17 @@ export const TAxios = (
|
||||
if (axiosInstance) {
|
||||
axiosInstance
|
||||
.then((res) => {
|
||||
console.log("TAxios response", url, res);
|
||||
console.log('TAxios response', url, res);
|
||||
|
||||
const apiSysStatus = res.headers["api-sys-status"];
|
||||
const apiSysMessage = res.headers["api-sys-message"];
|
||||
const apiSysStatus = res.headers['api-sys-status'];
|
||||
const apiSysMessage = res.headers['api-sys-message'];
|
||||
|
||||
const { systemNotice, systemTermination, appStatus } =
|
||||
getState().common;
|
||||
const { systemNotice, systemTermination, appStatus } = getState().common;
|
||||
const isInitialLoad = !appStatus.loadingComplete;
|
||||
|
||||
if (apiSysStatus === "800" && !systemNotice) {
|
||||
if (apiSysStatus === '800' && !systemNotice) {
|
||||
dispatch(setSystemNotice());
|
||||
} else if (apiSysStatus === "900" && !systemTermination) {
|
||||
} else if (apiSysStatus === '900' && !systemTermination) {
|
||||
const decodedMessage = decodeMessage(apiSysMessage);
|
||||
|
||||
dispatch(setSystemTermination(isInitialLoad));
|
||||
@@ -147,7 +143,7 @@ export const TAxios = (
|
||||
},
|
||||
})
|
||||
);
|
||||
} else if (apiSysStatus === "901" && !systemTermination) {
|
||||
} else if (apiSysStatus === '901' && !systemTermination) {
|
||||
const decodedMessage = decodeMessage(apiSysMessage);
|
||||
|
||||
dispatch(setSystemTermination(isInitialLoad));
|
||||
@@ -164,14 +160,9 @@ export const TAxios = (
|
||||
|
||||
if (baseUrl === URLS.GET_AUTHENTICATION_CODE) {
|
||||
if (res?.data?.retCode !== 0) {
|
||||
console.error("accessToken failed", res.data.retCode);
|
||||
console.error('accessToken failed', res.data.retCode);
|
||||
dispatch(
|
||||
showError(
|
||||
res.data.retCode,
|
||||
res.data.retMsg,
|
||||
false,
|
||||
res.data.retDetailCode
|
||||
)
|
||||
showError(res.data.retCode, res.data.retMsg, false, res.data.retDetailCode)
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -234,7 +225,7 @@ export const TAxios = (
|
||||
if (onSuccess) onSuccess(res);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("TAxios ", url, error);
|
||||
console.error('TAxios ', url, error);
|
||||
if (onFail) onFail(error);
|
||||
});
|
||||
}
|
||||
@@ -276,7 +267,7 @@ export const TAxiosPromise = (
|
||||
success: true,
|
||||
data: response.data,
|
||||
response: response,
|
||||
error: null
|
||||
error: null,
|
||||
});
|
||||
},
|
||||
// onFail - 에러도 resolve로 처리하여 throw 방지
|
||||
@@ -286,7 +277,7 @@ export const TAxiosPromise = (
|
||||
success: false,
|
||||
data: null,
|
||||
response: null,
|
||||
error: error
|
||||
error: error,
|
||||
});
|
||||
},
|
||||
noTokenRefresh
|
||||
@@ -329,7 +320,7 @@ export const TAxiosAdvancedPromise = (
|
||||
success: false,
|
||||
data: null,
|
||||
response: null,
|
||||
error: timeoutError
|
||||
error: timeoutError,
|
||||
});
|
||||
}
|
||||
}, timeout);
|
||||
@@ -349,14 +340,14 @@ export const TAxiosAdvancedPromise = (
|
||||
success: true,
|
||||
data: response.data,
|
||||
response: response,
|
||||
error: null
|
||||
error: null,
|
||||
});
|
||||
},
|
||||
// onFail
|
||||
(error) => {
|
||||
clearTimeout(timeoutId);
|
||||
console.error(`TAxiosPromise error on attempt ${attempts} for ${baseUrl}:`, error);
|
||||
|
||||
|
||||
// 재시도 로직
|
||||
if (attempts < maxAttempts) {
|
||||
console.log(`Retrying in ${retryDelay}ms... (${attempts}/${maxAttempts})`);
|
||||
@@ -372,7 +363,7 @@ export const TAxiosAdvancedPromise = (
|
||||
success: false,
|
||||
data: null,
|
||||
response: null,
|
||||
error: error
|
||||
error: error,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -387,22 +378,38 @@ export const TAxiosAdvancedPromise = (
|
||||
|
||||
// HTTP 메소드별 편의 함수들 (안전한 버전)
|
||||
export const TAxiosGet = async (dispatch, getState, baseUrl, urlParams = {}, options = {}) => {
|
||||
return await TAxiosPromise(dispatch, getState, 'get', baseUrl, urlParams, {}, options.noTokenRefresh);
|
||||
return await TAxiosPromise(
|
||||
dispatch,
|
||||
getState,
|
||||
'get',
|
||||
baseUrl,
|
||||
urlParams,
|
||||
{},
|
||||
options.noTokenRefresh
|
||||
);
|
||||
};
|
||||
|
||||
export const TAxiosPost = async (dispatch, getState, baseUrl, params = {}, options = {}) => {
|
||||
return await TAxiosPromise(dispatch, getState, 'post', baseUrl, {}, params, options.noTokenRefresh);
|
||||
return await TAxiosPromise(
|
||||
dispatch,
|
||||
getState,
|
||||
'post',
|
||||
baseUrl,
|
||||
{},
|
||||
params,
|
||||
options.noTokenRefresh
|
||||
);
|
||||
};
|
||||
|
||||
// 안전한 다중 요청 처리
|
||||
export const TAxiosAll = async (requests) => {
|
||||
try {
|
||||
const results = await Promise.all(requests);
|
||||
|
||||
|
||||
// 모든 결과를 안전하게 처리
|
||||
const successResults = [];
|
||||
const failedResults = [];
|
||||
|
||||
|
||||
results.forEach((result, index) => {
|
||||
if (result.success) {
|
||||
successResults.push({ index, result: result.data });
|
||||
@@ -410,12 +417,12 @@ export const TAxiosAll = async (requests) => {
|
||||
failedResults.push({ index, error: result.error });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return {
|
||||
success: failedResults.length === 0,
|
||||
successResults,
|
||||
failedResults,
|
||||
allResults: results
|
||||
allResults: results,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('TAxiosAll unexpected error:', error);
|
||||
@@ -423,7 +430,7 @@ export const TAxiosAll = async (requests) => {
|
||||
success: false,
|
||||
successResults: [],
|
||||
failedResults: [{ index: -1, error }],
|
||||
allResults: []
|
||||
allResults: [],
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -432,7 +439,7 @@ export const TAxiosAll = async (requests) => {
|
||||
export const TAxiosSequential = async (requests) => {
|
||||
const results = [];
|
||||
const errors = [];
|
||||
|
||||
|
||||
for (let i = 0; i < requests.length; i++) {
|
||||
try {
|
||||
const result = await requests[i];
|
||||
@@ -447,44 +454,42 @@ export const TAxiosSequential = async (requests) => {
|
||||
console.error(`TAxiosSequential unexpected error at request ${i}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
success: errors.length === 0,
|
||||
results,
|
||||
errors
|
||||
errors,
|
||||
};
|
||||
};
|
||||
|
||||
// 안전한 Redux Thunk 헬퍼
|
||||
export const createSafeApiThunk = (apiCall) => {
|
||||
return (...args) => async (dispatch, getState) => {
|
||||
try {
|
||||
const result = await apiCall(dispatch, getState, ...args);
|
||||
return result; // 이미 안전한 형태로 반환됨
|
||||
} catch (error) {
|
||||
console.error('API thunk unexpected error:', error);
|
||||
return {
|
||||
success: false,
|
||||
data: null,
|
||||
response: null,
|
||||
error
|
||||
};
|
||||
}
|
||||
};
|
||||
return (...args) =>
|
||||
async (dispatch, getState) => {
|
||||
try {
|
||||
const result = await apiCall(dispatch, getState, ...args);
|
||||
return result; // 이미 안전한 형태로 반환됨
|
||||
} catch (error) {
|
||||
console.error('API thunk unexpected error:', error);
|
||||
return {
|
||||
success: false,
|
||||
data: null,
|
||||
response: null,
|
||||
error,
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 실제 사용 예시들 (안전한 버전)
|
||||
export const safeUsageExamples = {
|
||||
// 1. 기본 안전한 사용법
|
||||
basicSafeUsage: async (dispatch, getState) => {
|
||||
const result = await TAxiosPromise(
|
||||
dispatch,
|
||||
getState,
|
||||
'get',
|
||||
URLS.GET_HOME_TERMS,
|
||||
{ trmsTpCdList: "MST00401, MST00402", mbrNo: "12345" }
|
||||
);
|
||||
|
||||
const result = await TAxiosPromise(dispatch, getState, 'get', URLS.GET_HOME_TERMS, {
|
||||
trmsTpCdList: 'MST00401, MST00402',
|
||||
mbrNo: '12345',
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
console.log('Success:', result.data);
|
||||
return result.data;
|
||||
@@ -497,78 +502,75 @@ export const safeUsageExamples = {
|
||||
|
||||
// 2. retCode 체크를 포함한 안전한 처리
|
||||
safeWithRetCodeCheck: async (dispatch, getState) => {
|
||||
const result = await TAxiosGet(
|
||||
dispatch,
|
||||
getState,
|
||||
URLS.GET_HOME_TERMS,
|
||||
{ trmsTpCdList: "MST00401, MST00402", mbrNo: "12345" }
|
||||
);
|
||||
|
||||
const result = await TAxiosGet(dispatch, getState, URLS.GET_HOME_TERMS, {
|
||||
trmsTpCdList: 'MST00401, MST00402',
|
||||
mbrNo: '12345',
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
console.error('Network error:', result.error);
|
||||
return { success: false, message: '네트워크 오류가 발생했습니다.' };
|
||||
}
|
||||
|
||||
|
||||
if (result.data.retCode !== 0) {
|
||||
console.error('API error:', result.data.retCode, result.data.retMsg);
|
||||
return {
|
||||
success: false,
|
||||
message: result.data.retMsg || 'API 오류가 발생했습니다.'
|
||||
return {
|
||||
success: false,
|
||||
message: result.data.retMsg || 'API 오류가 발생했습니다.',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
return { success: true, data: result.data };
|
||||
},
|
||||
|
||||
// 3. 여러 요청의 안전한 처리
|
||||
safeParallelRequests: async (dispatch, getState) => {
|
||||
const requests = [
|
||||
TAxiosGet(dispatch, getState, URLS.GET_HOME_TERMS, { mbrNo: "12345" }),
|
||||
TAxiosGet(dispatch, getState, URLS.GET_USER_INFO, { mbrNo: "12345" }),
|
||||
TAxiosPost(dispatch, getState, URLS.UPDATE_SETTINGS, { setting: "value" })
|
||||
TAxiosGet(dispatch, getState, URLS.GET_HOME_TERMS, { mbrNo: '12345' }),
|
||||
TAxiosGet(dispatch, getState, URLS.GET_USER_INFO, { mbrNo: '12345' }),
|
||||
TAxiosPost(dispatch, getState, URLS.UPDATE_SETTINGS, { setting: 'value' }),
|
||||
];
|
||||
|
||||
|
||||
const result = await TAxiosAll(requests);
|
||||
|
||||
|
||||
if (result.success) {
|
||||
console.log('All requests succeeded');
|
||||
return result.successResults.map(item => item.result);
|
||||
return result.successResults.map((item) => item.result);
|
||||
} else {
|
||||
console.error('Some requests failed:', result.failedResults);
|
||||
// 부분적 성공도 처리 가능
|
||||
return {
|
||||
successData: result.successResults.map(item => item.result),
|
||||
errors: result.failedResults
|
||||
successData: result.successResults.map((item) => item.result),
|
||||
errors: result.failedResults,
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
// 컴포넌트에서의 안전한 사용법
|
||||
export const ComponentUsageExample = () => {
|
||||
const dispatch = useDispatch();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
|
||||
const handleFetchTerms = async () => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
|
||||
const result = await dispatch(fetchCurrentUserHomeTermsSafe());
|
||||
|
||||
|
||||
setLoading(false);
|
||||
|
||||
|
||||
if (result.success) {
|
||||
console.log("Terms fetched successfully");
|
||||
console.log('Terms fetched successfully');
|
||||
// 성공 처리 (예: 성공 토스트 표시)
|
||||
} else {
|
||||
console.error("Failed to fetch terms:", result.message);
|
||||
console.error('Failed to fetch terms:', result.message);
|
||||
setError(result.message);
|
||||
// 에러 처리 (예: 에러 토스트 표시)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button onClick={handleFetchTerms} disabled={loading}>
|
||||
@@ -577,4 +579,4 @@ export const ComponentUsageExample = () => {
|
||||
{error && <div className="error-message">{error}</div>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user