가상매매 시간봉 제거

This commit is contained in:
Macbook
2026-05-28 20:48:28 +09:00
parent 7e3644cb62
commit 15160f7d2c
45 changed files with 996 additions and 405 deletions
+39 -6
View File
@@ -54,6 +54,8 @@ import { migrateLocalStorageToUiPreferences } from '../utils/uiPreferencesMigrat
// 전역 캐시 — 여러 컴포넌트에서 공유하여 중복 요청 방지
let _cache: AppSettingsDto | null = null;
let _loadPromise: Promise<AppSettingsDto> | null = null;
/** invalidate 이후 완료된 로드만 캐시에 반영 */
let _loadGeneration = 0;
type AppSettingsListener = () => void;
const _listeners = new Set<AppSettingsListener>();
@@ -74,20 +76,31 @@ export function subscribeAppSettings(listener: AppSettingsListener): () => void
function ensureLoaded(): Promise<AppSettingsDto> {
if (_cache !== null) return Promise.resolve(_cache);
if (_loadPromise) return _loadPromise;
const generation = _loadGeneration;
_loadPromise = loadAppSettings().then(async data => {
if (generation !== _loadGeneration) {
_loadPromise = null;
return _cache ?? {};
}
_cache = data ?? {};
const migrated = migrateLocalStorageToUiPreferences(_cache);
if (migrated?.changed) {
try {
const saved = await saveAppSettings({ uiPreferences: migrated.uiPreferences });
_cache = { ..._cache, ...saved, uiPreferences: migrated.uiPreferences };
if (generation === _loadGeneration) {
_cache = { ..._cache, ...saved, uiPreferences: migrated.uiPreferences };
}
} catch (e) {
console.warn('[useAppSettings] uiPreferences 마이그레이션 저장 실패:', e);
_cache = { ..._cache, uiPreferences: migrated.uiPreferences };
if (generation === _loadGeneration) {
_cache = { ..._cache, uiPreferences: migrated.uiPreferences };
}
}
}
_loadPromise = null;
notifyAppSettingsListeners();
if (generation === _loadGeneration) {
notifyAppSettingsListeners();
}
return _cache;
});
return _loadPromise;
@@ -96,6 +109,7 @@ function ensureLoaded(): Promise<AppSettingsDto> {
export function invalidateAppSettingsCache() {
_cache = null;
_loadPromise = null;
_loadGeneration += 1;
}
/** 서버에서 app-settings 재로드 후 캐시 갱신 (모바일 ↻ 동기화 등) */
@@ -167,13 +181,32 @@ export function resolveAppDefaults(s: AppSettingsDto) {
/** sessionKey 변경 시(로그인/로그아웃) 설정을 DB에서 다시 로드 */
export function useAppSettings(sessionKey = 0) {
const [settings, setSettings] = useState<AppSettingsDto>(_cache ?? {});
const [isLoaded, setIsLoaded] = useState(false);
const [isLoaded, setIsLoaded] = useState(_cache !== null);
const mountedRef = useRef(true);
const prevSessionKeyRef = useRef(sessionKey);
useEffect(() => {
mountedRef.current = true;
setIsLoaded(false);
invalidateAppSettingsCache();
const sessionChanged = prevSessionKeyRef.current !== sessionKey;
prevSessionKeyRef.current = sessionKey;
if (sessionChanged) {
if (_cache !== null) {
setSettings(_cache);
setDisplayTimezone(normalizeTimezone(_cache.displayTimezone ?? DEFAULT_DISPLAY_TIMEZONE));
setIsLoaded(true);
} else {
setIsLoaded(false);
invalidateAppSettingsCache();
}
} else if (_cache !== null) {
setSettings(_cache);
setDisplayTimezone(normalizeTimezone(_cache.displayTimezone ?? DEFAULT_DISPLAY_TIMEZONE));
setIsLoaded(true);
} else {
setIsLoaded(false);
}
ensureLoaded().then(data => {
if (mountedRef.current) {
setSettings(data);