[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:
2025-10-18 23:31:29 +09:00
parent 5bddacb3af
commit 0781bb39b2
7 changed files with 2272 additions and 522 deletions

View File

@@ -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>
);
};
};