feat(drafts): persist chat drafts in localStorage
- load drafts from localStorage on startup - write drafts to localStorage on update/clear - keep per-chat draft restore across page reload
This commit is contained in:
@@ -2,6 +2,42 @@ import { create } from "zustand";
|
|||||||
import { getChats, getMessages, updateMessageStatus } from "../api/chats";
|
import { getChats, getMessages, updateMessageStatus } from "../api/chats";
|
||||||
import type { Chat, DeliveryStatus, Message, MessageType } from "../chat/types";
|
import type { Chat, DeliveryStatus, Message, MessageType } from "../chat/types";
|
||||||
|
|
||||||
|
const DRAFTS_STORAGE_KEY = "bm_drafts_v1";
|
||||||
|
|
||||||
|
function loadDraftsFromStorage(): Record<number, string> {
|
||||||
|
if (typeof window === "undefined") {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const raw = window.localStorage.getItem(DRAFTS_STORAGE_KEY);
|
||||||
|
if (!raw) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const parsed = JSON.parse(raw) as Record<string, string>;
|
||||||
|
const result: Record<number, string> = {};
|
||||||
|
for (const [key, value] of Object.entries(parsed)) {
|
||||||
|
const chatId = Number(key);
|
||||||
|
if (Number.isFinite(chatId) && typeof value === "string") {
|
||||||
|
result[chatId] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveDraftsToStorage(drafts: Record<number, string>): void {
|
||||||
|
if (typeof window === "undefined") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
window.localStorage.setItem(DRAFTS_STORAGE_KEY, JSON.stringify(drafts));
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface ChatState {
|
interface ChatState {
|
||||||
chats: Chat[];
|
chats: Chat[];
|
||||||
activeChatId: number | null;
|
activeChatId: number | null;
|
||||||
@@ -52,7 +88,7 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
|||||||
chats: [],
|
chats: [],
|
||||||
activeChatId: null,
|
activeChatId: null,
|
||||||
messagesByChat: {},
|
messagesByChat: {},
|
||||||
draftsByChat: {},
|
draftsByChat: loadDraftsFromStorage(),
|
||||||
hasMoreByChat: {},
|
hasMoreByChat: {},
|
||||||
loadingMoreByChat: {},
|
loadingMoreByChat: {},
|
||||||
typingByChat: {},
|
typingByChat: {},
|
||||||
@@ -331,12 +367,14 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
|||||||
})
|
})
|
||||||
})),
|
})),
|
||||||
setDraft: (chatId, text) =>
|
setDraft: (chatId, text) =>
|
||||||
set((state) => ({
|
set((state) => {
|
||||||
draftsByChat: {
|
const nextDrafts = {
|
||||||
...state.draftsByChat,
|
...state.draftsByChat,
|
||||||
[chatId]: text
|
[chatId]: text
|
||||||
}
|
};
|
||||||
})),
|
saveDraftsToStorage(nextDrafts);
|
||||||
|
return { draftsByChat: nextDrafts };
|
||||||
|
}),
|
||||||
clearDraft: (chatId) =>
|
clearDraft: (chatId) =>
|
||||||
set((state) => {
|
set((state) => {
|
||||||
if (!(chatId in state.draftsByChat)) {
|
if (!(chatId in state.draftsByChat)) {
|
||||||
@@ -344,6 +382,7 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
|||||||
}
|
}
|
||||||
const next = { ...state.draftsByChat };
|
const next = { ...state.draftsByChat };
|
||||||
delete next[chatId];
|
delete next[chatId];
|
||||||
|
saveDraftsToStorage(next);
|
||||||
return { draftsByChat: next };
|
return { draftsByChat: next };
|
||||||
}),
|
}),
|
||||||
setFocusedMessage: (chatId, messageId) =>
|
setFocusedMessage: (chatId, messageId) =>
|
||||||
|
|||||||
Reference in New Issue
Block a user