PluginProbe
Code Snippets / 3.10.2
Code Snippets v3.10.2
4.0.0-beta.2 3.10.2 3.10.1 3.10.0 3.10.0-beta.2 3.10.0-beta.1 4.0.0-beta.1 3.9.6 trunk 2.10.0 2.10.1 2.12.0 2.12.1 2.13.0 2.13.1 2.13.2 2.13.3 2.14.0 2.14.1 2.14.2 2.14.3 2.14.4 2.14.5 2.14.6 3.0.0 All 65 releases
code-snippets / js / components / EditMenu / SnippetForm / WithSnippetFormContext.tsx

WithSnippetFormContext.tsx in Code Snippets 3.10.2, at js/components/EditMenu/SnippetForm/WithSnippetFormContext.tsx

109 lines 3.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { isAxiosError } from 'axios'
2 import React, { useCallback, useMemo, useState } from 'react'
3 import { createContextHook } from '../../../utils/bootstrap'
4 import { isLicensed } from '../../../utils/screen'
5 import { isProSnippet } from '../../../utils/snippets/snippets'
6 import type { Dispatch, PropsWithChildren, SetStateAction } from 'react'
7 import type { ScreenNotice } from '../../../types/ScreenNotice'
8 import type { Snippet } from '../../../types/Snippet'
9 import type { CodeEditorInstance } from '../../../types/vendor/WordPressCodeEditor'
10
11 export interface SnippetFormContext {
12 snippet: Snippet
13 isWorking: boolean
14 isReadOnly: boolean
15 isDirty: boolean
16 setSnippet: Dispatch<SetStateAction<Snippet>>
17 acceptSnippet: (snippet: Snippet) => void
18 updateSnippet: Dispatch<SetStateAction<Snippet>>
19 setIsWorking: Dispatch<SetStateAction<boolean>>
20 currentNotice: ScreenNotice | undefined
21 setCurrentNotice: Dispatch<SetStateAction<ScreenNotice | undefined>>
22 codeEditorInstance: CodeEditorInstance | undefined
23 handleRequestError: (error: unknown, message?: string) => void
24 setCodeEditorInstance: Dispatch<SetStateAction<CodeEditorInstance | undefined>>
25 }
26
27 const [Context, useSnippetForm] = createContextHook<SnippetFormContext>('useSnippetForm')
28
29 export interface WithSnippetFormContextProps extends PropsWithChildren {
30 initialSnippet: () => Snippet
31 }
32
33 const getSnippetDraftState = (snippet: Snippet) => ({
34 name: snippet.name,
35 desc: snippet.desc,
36 code: snippet.code,
37 tags: snippet.tags,
38 scope: snippet.scope,
39 priority: snippet.priority,
40 active: snippet.active,
41 locked: snippet.locked,
42 network: snippet.network,
43 sharedNetwork: snippet.shared_network,
44 conditionId: snippet.conditionId
45 })
46
47 const isSnippetDraftDirty = (snippet: Snippet, savedSnippet: Snippet): boolean => {
48 const draftState = JSON.stringify(getSnippetDraftState(snippet))
49 const savedDraftState = JSON.stringify(getSnippetDraftState(savedSnippet))
50 return draftState !== savedDraftState
51 }
52
53 export const WithSnippetFormContext: React.FC<WithSnippetFormContextProps> = ({ children, initialSnippet }) => {
54 const [initialValue] = useState<Snippet>(initialSnippet)
55 const [snippet, setSnippet] = useState<Snippet>(initialValue)
56 const [savedSnippet, setSavedSnippet] = useState<Snippet>(initialValue)
57 const [isWorking, setIsWorking] = useState(false)
58 const [currentNotice, setCurrentNotice] = useState<ScreenNotice>()
59 const [codeEditorInstance, setCodeEditorInstance] = useState<CodeEditorInstance>()
60
61 const isReadOnly = useMemo(
62 () => snippet.locked || !isLicensed() && isProSnippet({ scope: snippet.scope }),
63 [snippet.locked, snippet.scope]
64 )
65 const isDirty = useMemo(
66 () => isSnippetDraftDirty(snippet, savedSnippet),
67 [snippet, savedSnippet]
68 )
69 const acceptSnippet = useCallback((value: Snippet) => {
70 setSnippet(value)
71 setSavedSnippet(value)
72 }, [])
73
74 const handleRequestError = useCallback((error: unknown, message?: string) => {
75 console.error('Request failed', error)
76 setIsWorking(false)
77 setCurrentNotice(['error', [message, isAxiosError(error) ? error.message : ''].filter(Boolean).join(' ')])
78 }, [setIsWorking, setCurrentNotice])
79
80 const updateSnippet: Dispatch<SetStateAction<Snippet>> = useCallback((value: SetStateAction<Snippet>) => {
81 setSnippet(previous => {
82 const updated = 'object' === typeof value ? value : value(previous)
83 codeEditorInstance?.codemirror.setValue(updated.code)
84 window.tinymce?.activeEditor.setContent(updated.desc)
85 return updated
86 })
87 }, [codeEditorInstance?.codemirror])
88
89 const value: SnippetFormContext = {
90 snippet,
91 isWorking,
92 isReadOnly,
93 isDirty,
94 setSnippet,
95 acceptSnippet,
96 setIsWorking,
97 updateSnippet,
98 currentNotice,
99 setCurrentNotice,
100 codeEditorInstance,
101 handleRequestError,
102 setCodeEditorInstance
103 }
104
105 return <Context.Provider value={value}>{children}</Context.Provider>
106 }
107
108 export { useSnippetForm }
109