Skip to content

Commit 35f77f4

Browse files
authored
Merge pull request #5386 from ConnectAI-E/feature/safeLocalStorage
fix: safaLocalStorage
2 parents d51d7b6 + 992c3a5 commit 35f77f4

File tree

8 files changed

+96
-26
lines changed

8 files changed

+96
-26
lines changed

app/components/chat.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ import {
6767
isVisionModel,
6868
isDalle3,
6969
showPlugins,
70+
safeLocalStorage,
7071
} from "../utils";
7172

7273
import { uploadImage as uploadImageRemote } from "@/app/utils/chat";
@@ -109,6 +110,8 @@ import { getClientConfig } from "../config/client";
109110
import { useAllModels } from "../utils/hooks";
110111
import { MultimodalContent } from "../client/api";
111112

113+
const localStorage = safeLocalStorage();
114+
112115
const Markdown = dynamic(async () => (await import("./markdown")).Markdown, {
113116
loading: () => <LoadingIcon />,
114117
});
@@ -941,7 +944,7 @@ function _Chat() {
941944
.onUserInput(userInput, attachImages)
942945
.then(() => setIsLoading(false));
943946
setAttachImages([]);
944-
localStorage.setItem(LAST_INPUT_KEY, userInput);
947+
chatStore.setLastInput(userInput);
945948
setUserInput("");
946949
setPromptHints([]);
947950
if (!isMobileScreen) inputRef.current?.focus();
@@ -1007,7 +1010,7 @@ function _Chat() {
10071010
userInput.length <= 0 &&
10081011
!(e.metaKey || e.altKey || e.ctrlKey)
10091012
) {
1010-
setUserInput(localStorage.getItem(LAST_INPUT_KEY) ?? "");
1013+
setUserInput(chatStore.lastInput ?? "");
10111014
e.preventDefault();
10121015
return;
10131016
}

app/components/error.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { ISSUE_URL } from "../constant";
88
import Locale from "../locales";
99
import { showConfirm } from "./ui-lib";
1010
import { useSyncStore } from "../store/sync";
11+
import { useChatStore } from "../store/chat";
1112

1213
interface IErrorBoundaryState {
1314
hasError: boolean;
@@ -30,8 +31,7 @@ export class ErrorBoundary extends React.Component<any, IErrorBoundaryState> {
3031
try {
3132
useSyncStore.getState().export();
3233
} finally {
33-
localStorage.clear();
34-
location.reload();
34+
useChatStore.getState().clearAllData();
3535
}
3636
}
3737

app/components/mask.tsx

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -426,16 +426,7 @@ export function MaskPage() {
426426
const maskStore = useMaskStore();
427427
const chatStore = useChatStore();
428428

429-
const [filterLang, setFilterLang] = useState<Lang | undefined>(
430-
() => localStorage.getItem("Mask-language") as Lang | undefined,
431-
);
432-
useEffect(() => {
433-
if (filterLang) {
434-
localStorage.setItem("Mask-language", filterLang);
435-
} else {
436-
localStorage.removeItem("Mask-language");
437-
}
438-
}, [filterLang]);
429+
const filterLang = maskStore.language;
439430

440431
const allMasks = maskStore
441432
.getAll()
@@ -542,9 +533,9 @@ export function MaskPage() {
542533
onChange={(e) => {
543534
const value = e.currentTarget.value;
544535
if (value === Locale.Settings.Lang.All) {
545-
setFilterLang(undefined);
536+
maskStore.setLanguage(undefined);
546537
} else {
547-
setFilterLang(value as Lang);
538+
maskStore.setLanguage(value as Lang);
548539
}
549540
}}
550541
>

app/locales/index.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@ import ar from "./ar";
1818
import bn from "./bn";
1919
import sk from "./sk";
2020
import { merge } from "../utils/merge";
21+
import { safeLocalStorage } from "@/app/utils";
2122

2223
import type { LocaleType } from "./cn";
2324
export type { LocaleType, PartialLocaleType } from "./cn";
2425

26+
const localStorage = safeLocalStorage();
27+
2528
const ALL_LANGS = {
2629
cn,
2730
en,
@@ -82,17 +85,11 @@ merge(fallbackLang, targetLang);
8285
export default fallbackLang as LocaleType;
8386

8487
function getItem(key: string) {
85-
try {
86-
return localStorage.getItem(key);
87-
} catch {
88-
return null;
89-
}
88+
return localStorage.getItem(key);
9089
}
9190

9291
function setItem(key: string, value: string) {
93-
try {
94-
localStorage.setItem(key, value);
95-
} catch {}
92+
localStorage.setItem(key, value);
9693
}
9794

9895
function getLanguage() {

app/store/chat.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ import { nanoid } from "nanoid";
2626
import { createPersistStore } from "../utils/store";
2727
import { collectModelsWithDefaultModel } from "../utils/model";
2828
import { useAccessStore } from "./access";
29-
import { isDalle3 } from "../utils";
29+
import { isDalle3, safeLocalStorage } from "../utils";
3030
import { indexedDBStorage } from "@/app/utils/indexedDB-storage";
3131

32+
const localStorage = safeLocalStorage();
33+
3234
export type ChatMessageTool = {
3335
id: string;
3436
index?: number;
@@ -179,6 +181,7 @@ function fillTemplateWith(input: string, modelConfig: ModelConfig) {
179181
const DEFAULT_CHAT_STATE = {
180182
sessions: [createEmptySession()],
181183
currentSessionIndex: 0,
184+
lastInput: "",
182185
};
183186

184187
export const useChatStore = createPersistStore(
@@ -701,6 +704,11 @@ export const useChatStore = createPersistStore(
701704
localStorage.clear();
702705
location.reload();
703706
},
707+
setLastInput(lastInput: string) {
708+
set({
709+
lastInput,
710+
});
711+
},
704712
};
705713

706714
return methods;

app/store/mask.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,12 @@ export type Mask = {
2323

2424
export const DEFAULT_MASK_STATE = {
2525
masks: {} as Record<string, Mask>,
26+
language: undefined as Lang | undefined,
2627
};
2728

28-
export type MaskState = typeof DEFAULT_MASK_STATE;
29+
export type MaskState = typeof DEFAULT_MASK_STATE & {
30+
language?: Lang | undefined;
31+
};
2932

3033
export const DEFAULT_MASK_AVATAR = "gpt-bot";
3134
export const createEmptyMask = () =>
@@ -102,6 +105,11 @@ export const useMaskStore = createPersistStore(
102105
search(text: string) {
103106
return Object.values(get().masks);
104107
},
108+
setLanguage(language: Lang | undefined) {
109+
set({
110+
language,
111+
});
112+
},
105113
}),
106114
{
107115
name: StoreKey.Mask,

app/utils.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,3 +318,63 @@ export function adapter(config: Record<string, unknown>) {
318318
: path;
319319
return fetch(fetchUrl as string, { ...rest, responseType: "text" });
320320
}
321+
322+
export function safeLocalStorage(): {
323+
getItem: (key: string) => string | null;
324+
setItem: (key: string, value: string) => void;
325+
removeItem: (key: string) => void;
326+
clear: () => void;
327+
} {
328+
let storage: Storage | null;
329+
330+
try {
331+
if (typeof window !== "undefined" && window.localStorage) {
332+
storage = window.localStorage;
333+
} else {
334+
storage = null;
335+
}
336+
} catch (e) {
337+
console.error("localStorage is not available:", e);
338+
storage = null;
339+
}
340+
341+
return {
342+
getItem(key: string): string | null {
343+
if (storage) {
344+
return storage.getItem(key);
345+
} else {
346+
console.warn(
347+
`Attempted to get item "${key}" from localStorage, but localStorage is not available.`,
348+
);
349+
return null;
350+
}
351+
},
352+
setItem(key: string, value: string): void {
353+
if (storage) {
354+
storage.setItem(key, value);
355+
} else {
356+
console.warn(
357+
`Attempted to set item "${key}" in localStorage, but localStorage is not available.`,
358+
);
359+
}
360+
},
361+
removeItem(key: string): void {
362+
if (storage) {
363+
storage.removeItem(key);
364+
} else {
365+
console.warn(
366+
`Attempted to remove item "${key}" from localStorage, but localStorage is not available.`,
367+
);
368+
}
369+
},
370+
clear(): void {
371+
if (storage) {
372+
storage.clear();
373+
} else {
374+
console.warn(
375+
"Attempted to clear localStorage, but localStorage is not available.",
376+
);
377+
}
378+
},
379+
};
380+
}

app/utils/indexedDB-storage.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { StateStorage } from "zustand/middleware";
22
import { get, set, del, clear } from "idb-keyval";
3+
import { safeLocalStorage } from "@/app/utils";
4+
5+
const localStorage = safeLocalStorage();
36

47
class IndexedDBStorage implements StateStorage {
58
public async getItem(name: string): Promise<string | null> {

0 commit comments

Comments
 (0)