From 984f1ea48bddad1925ad522746f3089989ada506 Mon Sep 17 00:00:00 2001 From: Uwayss Date: Wed, 4 Mar 2026 11:09:40 +0300 Subject: [PATCH 1/4] feat: add react-native-mmkv dependency --- package-lock.json | 23 +++++++++++++++++++++++ package.json | 1 + 2 files changed, 24 insertions(+) diff --git a/package-lock.json b/package-lock.json index 16cdab1..253e53a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "react-native": "0.79.6", "react-native-draggable-flatlist": "^4.0.3", "react-native-gesture-handler": "~2.24.0", + "react-native-mmkv": "^4.1.2", "react-native-reanimated": "~3.17.4", "react-native-safe-area-context": "5.4.0", "react-native-screens": "~4.11.1", @@ -10382,6 +10383,28 @@ "react-native": "*" } }, + "node_modules/react-native-mmkv": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/react-native-mmkv/-/react-native-mmkv-4.1.2.tgz", + "integrity": "sha512-6LHb2DQBXuo96Aues13EugmlWw/HAYuh3KoJoQNrC4JsBwn3J3KiRYAg2mCm5Je0VYq2YsmbgZG7XJwX/WFYZA==", + "license": "MIT", + "peerDependencies": { + "react": "*", + "react-native": "*", + "react-native-nitro-modules": "*" + } + }, + "node_modules/react-native-nitro-modules": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/react-native-nitro-modules/-/react-native-nitro-modules-0.34.1.tgz", + "integrity": "sha512-ga6MBmG5CXBJ69d7BXXOMZ4sI3mEz6Q5pOjV1lyWEV60B/Ma/zGJGBNowsix1wx74zQEvq7gf+O0ovgazE4IKA==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native-reanimated": { "version": "3.17.5", "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.17.5.tgz", diff --git a/package.json b/package.json index 278a240..5a3d91a 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "react-native": "0.79.6", "react-native-draggable-flatlist": "^4.0.3", "react-native-gesture-handler": "~2.24.0", + "react-native-mmkv": "^4.1.2", "react-native-reanimated": "~3.17.4", "react-native-safe-area-context": "5.4.0", "react-native-screens": "~4.11.1", From 31391cb49dfc24f5eb1bdc9765362a0961e0ea7b Mon Sep 17 00:00:00 2001 From: Uwayss Date: Wed, 4 Mar 2026 11:11:59 +0300 Subject: [PATCH 2/4] feat: implement mmkv storage and migrate from file system --- src/core/storage/storageService.ts | 50 ++++++++++++++++++++---------- src/core/store/appStore.ts | 10 +++--- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/core/storage/storageService.ts b/src/core/storage/storageService.ts index 8c6221e..2e98049 100644 --- a/src/core/storage/storageService.ts +++ b/src/core/storage/storageService.ts @@ -1,38 +1,56 @@ // src/core/storage/storageService.ts import * as FileSystem from 'expo-file-system'; +import { createMMKV } from 'react-native-mmkv'; import { AppData } from '../store/appStore'; -const dataFilePath = `${FileSystem.documentDirectory}muhsinData.json`; +const storage = createMMKV(); +const DATA_KEY = 'muhsinData'; +const legacyDataFilePath = `${FileSystem.documentDirectory}muhsinData.json`; /** - * Loads the application data from the file system. + * Loads the application data from storage. + * It will first try to load from MMKV. If it's not found, it will attempt + * to migrate from the legacy file system. * @returns {Promise} The parsed data or null if it doesn't exist. */ -export const loadDataFromFile = async (): Promise => { +export const loadData = async (): Promise => { try { - const fileInfo = await FileSystem.getInfoAsync(dataFilePath); - if (!fileInfo.exists) { - console.log('Data file does not exist. Starting fresh.'); - return null; + // 1. Try to load from MMKV (new storage) + const storedData = storage.getString(DATA_KEY); + if (storedData) { + return JSON.parse(storedData) as AppData; } - const content = await FileSystem.readAsStringAsync(dataFilePath); - return JSON.parse(content) as AppData; + + // 2. If no data in MMKV, try to migrate from FileSystem (legacy storage) + console.log('No data in MMKV. Checking legacy FileSystem storage...'); + const fileInfo = await FileSystem.getInfoAsync(legacyDataFilePath); + if (fileInfo.exists) { + const content = await FileSystem.readAsStringAsync(legacyDataFilePath); + const data = JSON.parse(content) as AppData; + + // Migrate to MMKV + console.log('Migrating legacy data to MMKV...'); + saveData(data); + + return data; + } + + console.log('No legacy data found. Starting fresh.'); + return null; } catch (error) { - console.error('Failed to load data from file:', error); - // In case of parsing error, etc., we treat it as no data found. + console.error('Failed to load data from storage:', error); return null; } }; /** - * Saves the application data to the file system. + * Saves the application data to MMKV storage. * @param {AppData} data The data to save. */ -export const saveDataToFile = async (data: AppData): Promise => { +export const saveData = (data: AppData): void => { try { - const content = JSON.stringify(data, null, 2); // Pretty print JSON - await FileSystem.writeAsStringAsync(dataFilePath, content); + storage.set(DATA_KEY, JSON.stringify(data)); } catch (error) { - console.error('Failed to save data to file:', error); + console.error('Failed to save data to MMKV:', error); } }; diff --git a/src/core/store/appStore.ts b/src/core/store/appStore.ts index e8523c1..9903c22 100644 --- a/src/core/store/appStore.ts +++ b/src/core/store/appStore.ts @@ -2,7 +2,7 @@ import { create } from 'zustand'; import { Deed, DeedLog, DeedStatus } from '../data/models'; import { GENERIC_STATUSES, MOCK_DEEDS, MOCK_LOGS, SUGGESTED_DEEDS } from '../data/mock'; -import { loadDataFromFile, saveDataToFile } from '../storage/storageService'; +import { loadData, saveData } from '../storage/storageService'; import { formatISO } from 'date-fns'; import { Alert, Appearance, I18nManager } from 'react-native'; import { generateDemoLogs } from '../data/demoData'; @@ -82,7 +82,7 @@ const persistState = (state: AppState) => { dataToSave.logs = loadedData.logs; } - saveDataToFile(dataToSave); + saveData(dataToSave); }; const useAppStore = create((set, get) => ({ @@ -96,7 +96,7 @@ const useAppStore = create((set, get) => ({ // --- ACTIONS --- initialize: async () => { - const loadedData = await loadDataFromFile(); + const loadedData = await loadData(); let settings = defaultSettings; let initialDeeds = MOCK_DEEDS; let initialLogs = MOCK_LOGS; @@ -310,7 +310,7 @@ const useAppStore = create((set, get) => ({ Alert.alert(i18n.t('alerts.demoModeEnabledTitle'), i18n.t('alerts.demoModeEnabledMessage')); } else { // Disabling Demo Mode: Reload user's original data from disk - const originalData = await loadDataFromFile(); + const originalData = await loadData(); set({ deeds: originalData?.deeds || MOCK_DEEDS, logs: originalData?.logs || [], @@ -334,7 +334,7 @@ const useAppStore = create((set, get) => ({ } else { Appearance.setColorScheme(theme); } - await saveDataToFile(initialState); + saveData(initialState); await cancelAllReminders(); }, From cfdd957843e297228c951906cffda204904867ae Mon Sep 17 00:00:00 2001 From: Uwayss Date: Wed, 4 Mar 2026 11:14:13 +0300 Subject: [PATCH 3/4] refactor: remove legacy migration and simplify storageService --- src/core/storage/storageService.ts | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/core/storage/storageService.ts b/src/core/storage/storageService.ts index 2e98049..0ccde3f 100644 --- a/src/core/storage/storageService.ts +++ b/src/core/storage/storageService.ts @@ -1,41 +1,21 @@ // src/core/storage/storageService.ts -import * as FileSystem from 'expo-file-system'; import { createMMKV } from 'react-native-mmkv'; import { AppData } from '../store/appStore'; const storage = createMMKV(); const DATA_KEY = 'muhsinData'; -const legacyDataFilePath = `${FileSystem.documentDirectory}muhsinData.json`; /** * Loads the application data from storage. - * It will first try to load from MMKV. If it's not found, it will attempt - * to migrate from the legacy file system. * @returns {Promise} The parsed data or null if it doesn't exist. */ export const loadData = async (): Promise => { try { - // 1. Try to load from MMKV (new storage) const storedData = storage.getString(DATA_KEY); if (storedData) { return JSON.parse(storedData) as AppData; } - // 2. If no data in MMKV, try to migrate from FileSystem (legacy storage) - console.log('No data in MMKV. Checking legacy FileSystem storage...'); - const fileInfo = await FileSystem.getInfoAsync(legacyDataFilePath); - if (fileInfo.exists) { - const content = await FileSystem.readAsStringAsync(legacyDataFilePath); - const data = JSON.parse(content) as AppData; - - // Migrate to MMKV - console.log('Migrating legacy data to MMKV...'); - saveData(data); - - return data; - } - - console.log('No legacy data found. Starting fresh.'); return null; } catch (error) { console.error('Failed to load data from storage:', error); From cefc8404e986a1148320cec6cdfb51f3df3923ea Mon Sep 17 00:00:00 2001 From: Uwayss Date: Wed, 4 Mar 2026 11:20:56 +0300 Subject: [PATCH 4/4] fix: add missing react-native-nitro-modules dependency for mmkv --- package-lock.json | 2 +- package.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 253e53a..409aaad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,6 +30,7 @@ "react-native-draggable-flatlist": "^4.0.3", "react-native-gesture-handler": "~2.24.0", "react-native-mmkv": "^4.1.2", + "react-native-nitro-modules": "^0.34.1", "react-native-reanimated": "~3.17.4", "react-native-safe-area-context": "5.4.0", "react-native-screens": "~4.11.1", @@ -10399,7 +10400,6 @@ "resolved": "https://registry.npmjs.org/react-native-nitro-modules/-/react-native-nitro-modules-0.34.1.tgz", "integrity": "sha512-ga6MBmG5CXBJ69d7BXXOMZ4sI3mEz6Q5pOjV1lyWEV60B/Ma/zGJGBNowsix1wx74zQEvq7gf+O0ovgazE4IKA==", "license": "MIT", - "peer": true, "peerDependencies": { "react": "*", "react-native": "*" diff --git a/package.json b/package.json index 5a3d91a..8119f8a 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "react-native-draggable-flatlist": "^4.0.3", "react-native-gesture-handler": "~2.24.0", "react-native-mmkv": "^4.1.2", + "react-native-nitro-modules": "^0.34.1", "react-native-reanimated": "~3.17.4", "react-native-safe-area-context": "5.4.0", "react-native-screens": "~4.11.1",