v0.1.13 - 로컬·클라우드 데이터 분리

This commit is contained in:
2026-04-21 18:16:50 +09:00
parent 282d51daf6
commit a53ef4cc6f
5 changed files with 65 additions and 32 deletions

View File

@@ -16,6 +16,7 @@ import { fetchPlannerEntries, savePlannerEntry } from './lib/plannerApi'
import {
createInitialPlannerRecords,
persistPlannerState,
readPlannerStorageState,
restorePlannerUiState,
} from './lib/plannerStorage'
@@ -557,6 +558,7 @@ watch(
calendarViewDate: calendarViewDate.value,
statsRangeStart: normalizedStatsRange.value.startKey,
statsRangeEnd: normalizedStatsRange.value.endKey,
includeRecords: !isAuthenticated.value,
})
},
{ deep: true },
@@ -607,7 +609,6 @@ async function applyAuthSuccess(data) {
user: data.user,
})
await hydratePlannerRecordsFromApi()
queueSyncAllPlannerRecords()
closeAuthDialog()
}
@@ -672,6 +673,31 @@ function logout() {
syncStatus.value = 'local'
syncMessage.value = '로컬 저장 모드'
clearAuthState()
restoreLocalPlannerRecords()
}
function replacePlannerRecords(nextRecords) {
Object.keys(plannerRecords).forEach((key) => {
delete plannerRecords[key]
})
Object.entries(nextRecords).forEach(([key, record]) => {
plannerRecords[key] = record
})
}
function restoreLocalPlannerRecords() {
replacePlannerRecords(createInitialPlannerRecords(plannerSeed, normalizeRecord))
const savedState = readPlannerStorageState()
if (savedState.selectedDate) {
selectedDate.value = toDateValue(savedState.selectedDate, selectedDate.value)
}
if (savedState.calendarViewDate) {
calendarViewDate.value = toDateValue(savedState.calendarViewDate, selectedDate.value)
}
}
function findRecordKey(record) {
@@ -685,14 +711,6 @@ function clearPendingSyncTimers() {
syncTimers.clear()
}
function queueSyncAllPlannerRecords() {
Object.entries(plannerRecords).forEach(([key, record]) => {
if (hasPlannerContent(record)) {
schedulePlannerSync(key)
}
})
}
function schedulePlannerSyncForRecord(record) {
const recordKey = findRecordKey(record)
@@ -760,11 +778,14 @@ async function hydratePlannerRecordsFromApi() {
try {
const result = await fetchPlannerEntries(authToken.value)
const remoteRecords = {}
result.entries.forEach((entry) => {
plannerRecords[entry.entryDate] = normalizeRecord(entry.payload)
remoteRecords[entry.entryDate] = normalizeRecord(entry.payload)
})
replacePlannerRecords(remoteRecords)
syncStatus.value = 'cloud'
syncMessage.value = '클라우드 동기화 연결됨'
} catch (error) {

View File

@@ -13,6 +13,10 @@ function readStorageState() {
}
}
export function readPlannerStorageState() {
return readStorageState()
}
export function createInitialPlannerRecords(seedRecords, normalizeRecord) {
const baseRecords = Object.fromEntries(
Object.entries(seedRecords).map(([key, record]) => [key, normalizeRecord(record)]),
@@ -62,31 +66,37 @@ export function persistPlannerState({
calendarViewDate,
statsRangeStart,
statsRangeEnd,
includeRecords = true,
}) {
if (typeof window === 'undefined') {
return
}
const serializableRecords = Object.fromEntries(
Object.entries(plannerRecords).map(([key, record]) => [
key,
{
...record,
tasks: record.tasks.map((task) => ({ ...task })),
memo: record.memo.map((item) => ({ ...item })),
timetable: [...record.timetable],
},
]),
)
const previousState = readStorageState()
const nextState = {
...previousState,
selectedDate: selectedDate.toISOString(),
calendarViewDate: calendarViewDate.toISOString(),
statsRangeStart,
statsRangeEnd,
}
if (includeRecords) {
nextState.records = Object.fromEntries(
Object.entries(plannerRecords).map(([key, record]) => [
key,
{
...record,
tasks: record.tasks.map((task) => ({ ...task })),
memo: record.memo.map((item) => ({ ...item })),
timetable: [...record.timetable],
},
]),
)
}
window.localStorage.setItem(
STORAGE_KEY,
JSON.stringify({
selectedDate: selectedDate.toISOString(),
calendarViewDate: calendarViewDate.toISOString(),
statsRangeStart,
statsRangeEnd,
records: serializableRecords,
}),
JSON.stringify(nextState),
)
}