diff --git a/src/providers/problem-editor-provider.tsx b/src/providers/problem-editor-provider.tsx index eaef517..c5eeead 100644 --- a/src/providers/problem-editor-provider.tsx +++ b/src/providers/problem-editor-provider.tsx @@ -1,110 +1,66 @@ "use client"; -import type { +import { EditorLanguage, - EditorLanguageConfig, - LanguageServerConfig, - Template, + type EditorLanguageConfig, + type LanguageServerConfig, + type Template, } from "@prisma/client"; -import type { editor } from "monaco-editor"; -import { createStore, StoreApi, useStore } from "zustand"; -import { persist, createJSONStorage } from "zustand/middleware"; -import type { MonacoLanguageClient } from "monaco-languageclient"; -import { DEFAULT_EDITOR_LANGUAGE } from "@/config/editor-language"; -import { createContext, PropsWithChildren, useContext, useState } from "react"; +import { useStore } from "zustand"; +import { type ReactNode, createContext, useRef, useContext } from "react"; +import { type ProblemStore, createProblemStore } from "@/stores/problem-store"; -type ProblemEditorState = { - hydrated: boolean; - editor: editor.IStandaloneCodeEditor | null; - monacoLanguageClient: MonacoLanguageClient | null; - globalLang: EditorLanguage; - currentLang: EditorLanguage; - currentValue: string; +export type ProblemStoreApi = ReturnType; + +export const ProblemStoreContext = createContext( + undefined +); + +export interface ProblemStoreProviderProps { + children: ReactNode; problemId: string; templates: Template[]; editorLanguageConfigs: EditorLanguageConfig[]; languageServerConfigs: LanguageServerConfig[]; -}; +} -type ProblemEditorActions = { - setHydrated: (value: boolean) => void; - setEditor: (editor: editor.IStandaloneCodeEditor) => void; - setMonacoLanguageClient: (client: MonacoLanguageClient | null) => void; - setGlobalLang: (lang: EditorLanguage) => void; - setCurrentLang: (lang: EditorLanguage) => void; - setCurrentValue: (value: string) => void; -}; - -type ProblemEditorStore = ProblemEditorState & ProblemEditorActions; - -const ProblemEditorContext = createContext | undefined>(undefined); - -type ProblemEditorProviderProps = PropsWithChildren & { - problemId: string; - templates: Template[]; - editorLanguageConfigs: EditorLanguageConfig[]; - languageServerConfigs: LanguageServerConfig[]; -}; - -export function ProblemEditorProvider({ +export const ProblemStoreProvider = ({ children, problemId, templates, editorLanguageConfigs, languageServerConfigs, -}: ProblemEditorProviderProps) { - const [store] = useState(() => - createStore()( - persist( - (set) => ({ - hydrated: false, - editor: null, - monacoLanguageClient: null, - globalLang: DEFAULT_EDITOR_LANGUAGE, - currentLang: DEFAULT_EDITOR_LANGUAGE, - currentValue: "", - problemId, - templates, - editorLanguageConfigs, - languageServerConfigs, - setHydrated: (value) => set({ hydrated: value }), - setEditor: (editor) => set({ editor }), - setMonacoLanguageClient: (client) => set({ monacoLanguageClient: client }), - setGlobalLang: (lang) => set({ globalLang: lang }), - setCurrentLang: (lang) => set({ currentLang: lang }), - setCurrentValue: (value) => set({ currentValue: value }), - }), - { - name: "problem-store", - storage: createJSONStorage(() => localStorage), - partialize: (state) => ({ - globalLang: state.globalLang, - }), - onRehydrateStorage: () => { - return (state, error) => { - if (error) { - console.error("An error happened during hydration", error); - } else if (state) { - state.setHydrated(true); - } - }; - }, - } - ) - ) - ); +}: ProblemStoreProviderProps) => { + const storeRef = useRef(null); + + if (storeRef.current === null) { + storeRef.current = createProblemStore({ + hydrated: false, + editor: null, + monacoLanguageClient: null, + globalLang: EditorLanguage.c, + currentLang: EditorLanguage.c, + currentValue: "", + problemId, + templates, + editorLanguageConfigs, + languageServerConfigs, + }); + } return ( - + {children} - + ); -} +}; -export function useProblemEditorStore(selector: (state: ProblemEditorStore) => T) { - const context = useContext(ProblemEditorContext); - if (!context) { - throw new Error("ProblemEditorContext.Provider is missing."); +export const useProblemStore = (selector: (store: ProblemStore) => T): T => { + const problemStoreContext = useContext(ProblemStoreContext); + + if (!problemStoreContext) { + throw new Error("useProblemStore must be used within ProblemStoreProvider"); } - return useStore(context, selector); -} + + return useStore(problemStoreContext, selector); +};