mirror of
https://github.com/Qortal/qapp-core.git
synced 2025-06-14 17:41:20 +00:00
modified localstorage data
This commit is contained in:
parent
9663ab2459
commit
f0c1b956ac
11
package-lock.json
generated
11
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "qapp-core",
|
"name": "qapp-core",
|
||||||
"version": "1.0.19",
|
"version": "1.0.22",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "qapp-core",
|
"name": "qapp-core",
|
||||||
"version": "1.0.19",
|
"version": "1.0.22",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/react-virtual": "^3.13.2",
|
"@tanstack/react-virtual": "^3.13.2",
|
||||||
@ -15,6 +15,7 @@
|
|||||||
"compressorjs": "^1.2.1",
|
"compressorjs": "^1.2.1",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
|
"dexie": "^4.0.11",
|
||||||
"dompurify": "^3.2.4",
|
"dompurify": "^3.2.4",
|
||||||
"react-dropzone": "^14.3.8",
|
"react-dropzone": "^14.3.8",
|
||||||
"react-hot-toast": "^2.5.2",
|
"react-hot-toast": "^2.5.2",
|
||||||
@ -1871,6 +1872,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dexie": {
|
||||||
|
"version": "4.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/dexie/-/dexie-4.0.11.tgz",
|
||||||
|
"integrity": "sha512-SOKO002EqlvBYYKQSew3iymBoN2EQ4BDw/3yprjh7kAfFzjBYkaMNa/pZvcA7HSWlcKSQb9XhPe3wKyQ0x4A8A==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
"node_modules/dir-glob": {
|
"node_modules/dir-glob": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "qapp-core",
|
"name": "qapp-core",
|
||||||
"version": "1.0.22",
|
"version": "1.0.24",
|
||||||
"description": "Qortal's core React library with global state, UI components, and utilities",
|
"description": "Qortal's core React library with global state, UI components, and utilities",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"module": "dist/index.mjs",
|
"module": "dist/index.mjs",
|
||||||
@ -29,6 +29,7 @@
|
|||||||
"compressorjs": "^1.2.1",
|
"compressorjs": "^1.2.1",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
|
"dexie": "^4.0.11",
|
||||||
"dompurify": "^3.2.4",
|
"dompurify": "^3.2.4",
|
||||||
"react-dropzone": "^14.3.8",
|
"react-dropzone": "^14.3.8",
|
||||||
"react-hot-toast": "^2.5.2",
|
"react-hot-toast": "^2.5.2",
|
||||||
|
@ -4,7 +4,7 @@ import { useResources } from "../hooks/useResources";
|
|||||||
import { useAppInfo } from "../hooks/useAppInfo";
|
import { useAppInfo } from "../hooks/useAppInfo";
|
||||||
import { useIdentifiers } from "../hooks/useIdentifiers";
|
import { useIdentifiers } from "../hooks/useIdentifiers";
|
||||||
import { Toaster } from "react-hot-toast";
|
import { Toaster } from "react-hot-toast";
|
||||||
import { useLocalStorage } from "../hooks/useLocalStorage";
|
import { usePersistentStore } from "../hooks/usePersistentStore";
|
||||||
import { IndexManager } from "../components/IndexManager/IndexManager";
|
import { IndexManager } from "../components/IndexManager/IndexManager";
|
||||||
import { useIndexes } from "../hooks/useIndexes";
|
import { useIndexes } from "../hooks/useIndexes";
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ auth: ReturnType<typeof useAuth>;
|
|||||||
lists: ReturnType<typeof useResources>;
|
lists: ReturnType<typeof useResources>;
|
||||||
appInfo: ReturnType<typeof useAppInfo>;
|
appInfo: ReturnType<typeof useAppInfo>;
|
||||||
identifierOperations: ReturnType<typeof useIdentifiers>
|
identifierOperations: ReturnType<typeof useIdentifiers>
|
||||||
localStorageOperations: ReturnType<typeof useLocalStorage>
|
persistentOperations: ReturnType<typeof usePersistentStore>
|
||||||
indexOperations: ReturnType<typeof useIndexes>
|
indexOperations: ReturnType<typeof useIndexes>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,10 +48,10 @@ export const GlobalProvider = ({ children, config, toastStyle = {} }: GlobalProv
|
|||||||
const appInfo = useAppInfo(config.appName, config?.publicSalt)
|
const appInfo = useAppInfo(config.appName, config?.publicSalt)
|
||||||
const lists = useResources()
|
const lists = useResources()
|
||||||
const identifierOperations = useIdentifiers(config.publicSalt, config.appName)
|
const identifierOperations = useIdentifiers(config.publicSalt, config.appName)
|
||||||
const localStorageOperations = useLocalStorage(config.publicSalt, config.appName)
|
const persistentOperations = usePersistentStore(config.publicSalt, config.appName, auth?.address)
|
||||||
const indexOperations = useIndexes()
|
const indexOperations = useIndexes()
|
||||||
// ✅ Merge all hooks into a single `contextValue`
|
// ✅ Merge all hooks into a single `contextValue`
|
||||||
const contextValue = useMemo(() => ({ auth, lists, appInfo, identifierOperations, localStorageOperations, indexOperations }), [auth, lists, appInfo, identifierOperations, localStorageOperations]);
|
const contextValue = useMemo(() => ({ auth, lists, appInfo, identifierOperations, persistentOperations, indexOperations }), [auth, lists, appInfo, identifierOperations, persistentOperations]);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
import React, { useCallback, useEffect, useMemo } from "react";
|
|
||||||
import { useAppStore } from "../state/app";
|
|
||||||
import { EnumCollisionStrength, hashWord } from "../utils/encryption";
|
|
||||||
|
|
||||||
|
|
||||||
export const useLocalStorage = (publicSalt: string, appName: string) => {
|
|
||||||
|
|
||||||
|
|
||||||
const setTimestamp = useCallback(async (timestamp: number, storageId: string)=> {
|
|
||||||
const hashedString = await hashWord(`${appName}-${storageId}`, EnumCollisionStrength.HIGH, publicSalt)
|
|
||||||
localStorage.setItem(hashedString, JSON.stringify(timestamp));
|
|
||||||
return true
|
|
||||||
}, [appName, publicSalt])
|
|
||||||
|
|
||||||
const getTimestamp = useCallback(async ( storageId: string)=> {
|
|
||||||
const hashedString = await hashWord(`${appName}-${storageId}`, EnumCollisionStrength.HIGH, publicSalt)
|
|
||||||
const stored = localStorage.getItem(hashedString);
|
|
||||||
if(stored){
|
|
||||||
return JSON.parse(stored)
|
|
||||||
} else return null
|
|
||||||
}, [appName, publicSalt])
|
|
||||||
|
|
||||||
const isNewTimestamp = useCallback(async( storageId: string, differenceTimestamp: number)=> {
|
|
||||||
const hashedString = await hashWord(`${appName}-${storageId}`, EnumCollisionStrength.HIGH, publicSalt)
|
|
||||||
const stored = localStorage.getItem(hashedString);
|
|
||||||
if(stored){
|
|
||||||
const storedTimestamp = JSON.parse(stored)
|
|
||||||
return (Date.now() - storedTimestamp) > differenceTimestamp
|
|
||||||
} else return true
|
|
||||||
}, [appName, publicSalt])
|
|
||||||
return {
|
|
||||||
setTimestamp,
|
|
||||||
getTimestamp,
|
|
||||||
isNewTimestamp
|
|
||||||
|
|
||||||
};
|
|
||||||
};
|
|
88
src/hooks/usePersistentStore.tsx
Normal file
88
src/hooks/usePersistentStore.tsx
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import { useCallback } from 'react';
|
||||||
|
import { EnumCollisionStrength, hashWord } from '../utils/encryption';
|
||||||
|
import { db } from '../utils/persistentDb';
|
||||||
|
|
||||||
|
export const usePersistentStore = (
|
||||||
|
publicSalt: string,
|
||||||
|
appName: string,
|
||||||
|
qortalAddress?: string | null
|
||||||
|
) => {
|
||||||
|
const getHashedId = useCallback(
|
||||||
|
async (id: string) => {
|
||||||
|
const key = `${appName}-${qortalAddress ?? 'no-address'}-${id}`;
|
||||||
|
return await hashWord(key, EnumCollisionStrength.HIGH, publicSalt);
|
||||||
|
},
|
||||||
|
[appName, publicSalt, qortalAddress]
|
||||||
|
);
|
||||||
|
|
||||||
|
// --- TIMESTAMP FUNCTIONS ---
|
||||||
|
|
||||||
|
const setTimestamp = useCallback(
|
||||||
|
async (timestamp: number, storageId: string) => {
|
||||||
|
const id = await getHashedId(storageId);
|
||||||
|
await db.timestamps.put({ id, timestamp });
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
[getHashedId]
|
||||||
|
);
|
||||||
|
|
||||||
|
const getTimestamp = useCallback(
|
||||||
|
async (storageId: string) => {
|
||||||
|
const id = await getHashedId(storageId);
|
||||||
|
const entry = await db.timestamps.get(id);
|
||||||
|
return entry?.timestamp ?? null;
|
||||||
|
},
|
||||||
|
[getHashedId]
|
||||||
|
);
|
||||||
|
|
||||||
|
const isNewTimestamp = useCallback(
|
||||||
|
async (storageId: string, differenceTimestamp: number) => {
|
||||||
|
const id = await getHashedId(storageId);
|
||||||
|
const entry = await db.timestamps.get(id);
|
||||||
|
if (!entry) return true;
|
||||||
|
return Date.now() - entry.timestamp > differenceTimestamp;
|
||||||
|
},
|
||||||
|
[getHashedId]
|
||||||
|
);
|
||||||
|
|
||||||
|
// --- GENERIC CRUD FOR DYNAMIC DATA ---
|
||||||
|
|
||||||
|
const saveData = useCallback(
|
||||||
|
async (id: string, data: any) => {
|
||||||
|
const hashedId = await getHashedId(id);
|
||||||
|
await db.dynamicData.put({ id: hashedId, data });
|
||||||
|
},
|
||||||
|
[getHashedId]
|
||||||
|
);
|
||||||
|
|
||||||
|
const getData = useCallback(
|
||||||
|
async (id: string) => {
|
||||||
|
const hashedId = await getHashedId(id);
|
||||||
|
const entry = await db.dynamicData.get(hashedId);
|
||||||
|
return entry?.data ?? null;
|
||||||
|
},
|
||||||
|
[getHashedId]
|
||||||
|
);
|
||||||
|
|
||||||
|
const deleteData = useCallback(
|
||||||
|
async (id: string) => {
|
||||||
|
const hashedId = await getHashedId(id);
|
||||||
|
await db.dynamicData.delete(hashedId);
|
||||||
|
},
|
||||||
|
[getHashedId]
|
||||||
|
);
|
||||||
|
|
||||||
|
const listAllData = useCallback(async () => {
|
||||||
|
return await db.dynamicData.toArray();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return {
|
||||||
|
setTimestamp,
|
||||||
|
getTimestamp,
|
||||||
|
isNewTimestamp,
|
||||||
|
saveData,
|
||||||
|
getData,
|
||||||
|
deleteData,
|
||||||
|
listAllData,
|
||||||
|
};
|
||||||
|
};
|
26
src/utils/persistentDb.ts
Normal file
26
src/utils/persistentDb.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import Dexie, { Table } from 'dexie';
|
||||||
|
|
||||||
|
export interface TimestampEntry {
|
||||||
|
id: string; // hashed key
|
||||||
|
timestamp: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DynamicEntry {
|
||||||
|
id: string;
|
||||||
|
data: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AppDatabase extends Dexie {
|
||||||
|
timestamps!: Table<TimestampEntry>;
|
||||||
|
dynamicData!: Table<DynamicEntry>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super('MyAppDB');
|
||||||
|
this.version(1).stores({
|
||||||
|
timestamps: 'id',
|
||||||
|
dynamicData: 'id',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const db = new AppDatabase();
|
Loading…
x
Reference in New Issue
Block a user