Skip to content

Commit

Permalink
feat(fe): persist language and code datas (#1720)
Browse files Browse the repository at this point in the history
* feat(fe): persist language and code datas

* fix(fe): change a code store
  • Loading branch information
dayongkr authored and mnseok committed Jul 4, 2024
1 parent e59127c commit 1b984b7
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 60 deletions.
14 changes: 10 additions & 4 deletions apps/frontend/components/EditorHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,27 @@ import {
import { auth } from '@/lib/auth'
import { fetcherWithAuth } from '@/lib/utils'
import useAuthModalStore from '@/stores/authModal'
import useEditorStore from '@/stores/editor'
import { CodeContext, useLanguageStore } from '@/stores/editor'
import type { Language, ProblemDetail, Submission } from '@/types/type'
import JSConfetti from 'js-confetti'
import { Trash2Icon } from 'lucide-react'
import type { Route } from 'next'
import { useRouter } from 'next/navigation'
import { useEffect, useState } from 'react'
import { useContext, useEffect, useState } from 'react'
import { useInterval } from 'react-use'
import { toast } from 'sonner'
import { useStore } from 'zustand'

interface ProblemEditorProps {
problem: ProblemDetail
contestId?: number
}

export default function Editor({ problem, contestId }: ProblemEditorProps) {
const { code, language, clearCode, setLanguage } = useEditorStore()
const { language, setLanguage } = useLanguageStore()
const store = useContext(CodeContext)
if (!store) throw new Error('CodeContext is not provided')
const { code, setCode } = useStore(store)
const [loading, setLoading] = useState(false)
const [submissionId, setSubmissionId] = useState<number | null>(null)
const router = useRouter()
Expand Down Expand Up @@ -141,7 +145,9 @@ export default function Editor({ problem, contestId }: ProblemEditorProps) {
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter className="flex gap-2">
<AlertDialogAction onClick={clearCode}>Clear</AlertDialogAction>
<AlertDialogAction onClick={() => setCode('')}>
Clear
</AlertDialogAction>
<AlertDialogCancel>Cancel</AlertDialogCancel>
</AlertDialogFooter>
</AlertDialogContent>
Expand Down
44 changes: 19 additions & 25 deletions apps/frontend/components/EditorResizablePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import {
} from '@/components/ui/resizable'
import { ScrollArea } from '@/components/ui/scroll-area'
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { useStorage } from '@/lib/storage'
import useEditorStore from '@/stores/editor'
import { CodeContext, createCodeStore, useLanguageStore } from '@/stores/editor'
import type { Language, ProblemDetail } from '@/types/type'
import type { Route } from 'next'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import { Suspense, useEffect } from 'react'
import { Suspense, useContext, useEffect } from 'react'
import { useStore } from 'zustand'
import Loading from '../app/problem/[problemId]/loading'
import EditorHeader from './EditorHeader'

Expand All @@ -31,6 +31,13 @@ export default function EditorMainResizablePanel({
}: ProblemEditorProps) {
const pathname = usePathname()
const base = contestId ? `/contest/${contestId}` : ''
const { language, setLanguage } = useLanguageStore()
const store = createCodeStore(language, problem.id, contestId)
useEffect(() => {
if (!problem.languages.includes(language)) {
setLanguage(problem.languages[0])
}
}, [problem.languages, language, setLanguage])
return (
<ResizablePanelGroup
direction="horizontal"
Expand Down Expand Up @@ -82,34 +89,21 @@ export default function EditorMainResizablePanel({

<ResizablePanel defaultSize={65} className="bg-slate-900">
<div className="grid-rows-editor grid h-full">
<EditorHeader problem={problem} contestId={contestId} />
<CodeEditorInEditorResizablePanel problem={problem} />
<CodeContext.Provider value={store}>
<EditorHeader problem={problem} contestId={contestId} />
<CodeEditorInEditorResizablePanel />
</CodeContext.Provider>
</div>
</ResizablePanel>
</ResizablePanelGroup>
)
}

function CodeEditorInEditorResizablePanel({
problem
}: {
problem: ProblemDetail
}) {
// get programming language from localStorage for default value
const { value } = useStorage<Language>(
'programming_lang',
problem.languages[0]
)
const { code, setCode, setLanguage, language } = useEditorStore()

useEffect(() => {
if (!language) {
setLanguage(value ?? problem.languages[0])
} else if (language && !problem.languages.includes(language)) {
// if value in storage is not in languages, set value to the first language
setLanguage(problem.languages[0])
}
}, [problem.languages, value, setLanguage, language])
function CodeEditorInEditorResizablePanel() {
const { language } = useLanguageStore()
const store = useContext(CodeContext)
if (!store) throw new Error('CodeContext is not provided')
const { code, setCode } = useStore(store)
return (
<CodeEditor
value={code}
Expand Down
16 changes: 0 additions & 16 deletions apps/frontend/lib/storage.ts

This file was deleted.

59 changes: 44 additions & 15 deletions apps/frontend/stores/editor.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,52 @@
import type { Language } from '@/types/type'
import { create } from 'zustand'
import { createContext } from 'react'
import { create, createStore } from 'zustand'
import { persist } from 'zustand/middleware'

interface EditorStore {
code: string
interface LanguageStore {
language: Language
setLanguage: (language: Language) => void
}

export const useLanguageStore = create(
persist<LanguageStore>(
(set) => ({
language: 'C',
setLanguage: (language) => {
set({ language })
}
}),
{
name: 'language'
}
)
)
interface CodeState {
code: string
setCode: (code: string) => void
clearCode: () => void
}

const useEditorStore = create<EditorStore>((set) => ({
code: '',
language: 'C',
setLanguage: (language) => {
localStorage.setItem('programming_lang', language)
set({ language })
},
setCode: (code: string) => set({ code }),
clearCode: () => set({ code: '' })
}))
type CodeStore = ReturnType<typeof createCodeStore>

export const createCodeStore = (
language: Language,
problemId: number,
contestId?: number
) => {
const problemKey = `${problemId}${contestId ? `_${contestId}` : ''}_${language}`
return createStore<CodeState>()(
persist<CodeState>(
(set) => ({
code: '',
setCode: (code) => {
set({ code })
}
}),
{
name: problemKey
}
)
)
}

export default useEditorStore
export const CodeContext = createContext<CodeStore | null>(null)

0 comments on commit 1b984b7

Please sign in to comment.