perf(cache): implement event-driven long TTL cache optimization & fix contact renaming edge-case
This commit is contained in:
@@ -2788,7 +2788,6 @@
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
||||
@@ -140,6 +140,44 @@ function sortChats(chats: Chat[]): Chat[] {
|
||||
|
||||
// ─── Store ────────────────────────────────────────────────────────────────────
|
||||
|
||||
// ─── Cache local (localStorage) — UX instantâneo no reload ─────────────────────
|
||||
// Persiste os primeiros N chats por instância para hidratar a UI antes do fetch.
|
||||
// Chave: `inboxCache:v1:${instanceId}:${archived ? '1' : '0'}`
|
||||
// TTL implícito: validamos pela data salva e descartamos se > 7 dias.
|
||||
const INBOX_CACHE_PREFIX = 'inboxCache:v1'
|
||||
const INBOX_CACHE_LIMIT = 10
|
||||
const INBOX_CACHE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000
|
||||
|
||||
interface InboxCacheEntry {
|
||||
savedAt: number
|
||||
chats: Chat[]
|
||||
}
|
||||
|
||||
function inboxCacheKey(instanceId: string, archived: boolean): string {
|
||||
return `${INBOX_CACHE_PREFIX}:${instanceId}:${archived ? '1' : '0'}`
|
||||
}
|
||||
|
||||
function readInboxCache(instanceId: string, archived: boolean): Chat[] | null {
|
||||
if (typeof window === 'undefined') return null
|
||||
try {
|
||||
const raw = localStorage.getItem(inboxCacheKey(instanceId, archived))
|
||||
if (!raw) return null
|
||||
const parsed = JSON.parse(raw) as InboxCacheEntry
|
||||
if (!parsed || !Array.isArray(parsed.chats)) return null
|
||||
if (Date.now() - parsed.savedAt > INBOX_CACHE_MAX_AGE_MS) return null
|
||||
return parsed.chats
|
||||
} catch { return null }
|
||||
}
|
||||
|
||||
function writeInboxCache(instanceId: string, archived: boolean, chats: Chat[]): void {
|
||||
if (typeof window === 'undefined') return
|
||||
try {
|
||||
const slim = chats.slice(0, INBOX_CACHE_LIMIT)
|
||||
const entry: InboxCacheEntry = { savedAt: Date.now(), chats: slim }
|
||||
localStorage.setItem(inboxCacheKey(instanceId, archived), JSON.stringify(entry))
|
||||
} catch { /* quota exceeded — ignora */ }
|
||||
}
|
||||
|
||||
export const useChatStore = create<ChatState>()(
|
||||
immer((set, get) => ({
|
||||
chats: [],
|
||||
@@ -217,11 +255,34 @@ export const useChatStore = create<ChatState>()(
|
||||
// ── Async ─────────────────────────────────────────────────────────────────
|
||||
|
||||
loadChats: async (instanceId, opts = {}) => {
|
||||
set((s) => { s.chatsLoading = true })
|
||||
// Hidratação instantânea: se temos cache local válido para esta instância,
|
||||
// mostra os 10 chats salvos imediatamente enquanto a request real roda.
|
||||
// Evita tela em branco ou skeleton de 15s+ em redes lentas.
|
||||
const archivedFlag = opts.archived ?? false
|
||||
const hasSearch = !!opts.search
|
||||
const current = get().chats
|
||||
if (!hasSearch) {
|
||||
const sameInstance = current.length > 0 && current[0]?.instanceId === instanceId
|
||||
if (!sameInstance) {
|
||||
const cached = readInboxCache(instanceId, archivedFlag)
|
||||
if (cached && cached.length > 0) {
|
||||
set((s) => { s.chats = sortChats(cached); s.chatsLoading = true })
|
||||
} else {
|
||||
set((s) => { s.chatsLoading = true })
|
||||
}
|
||||
} else {
|
||||
set((s) => { s.chatsLoading = true })
|
||||
}
|
||||
} else {
|
||||
set((s) => { s.chatsLoading = true })
|
||||
}
|
||||
|
||||
try {
|
||||
const raw = await chatApi.list(instanceId, opts)
|
||||
const data: Chat[] = (Array.isArray(raw) ? raw : []).map(mapBackendChat)
|
||||
set((s) => { s.chats = sortChats(data); s.chatsLoading = false })
|
||||
const sorted = sortChats(data)
|
||||
set((s) => { s.chats = sorted; s.chatsLoading = false })
|
||||
if (!hasSearch) writeInboxCache(instanceId, archivedFlag, sorted)
|
||||
} catch {
|
||||
set((s) => { s.chatsLoading = false })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user