← All changes
|
js/components/EditMenu/SnippetForm/WithSnippetFormContext.tsx
+36
-2
4.0.0-beta.1
→
trunk
View file →
| @@ -5,15 +5,17 @@ | ||
| 5 | 5 | import { isProSnippet } from '../../../utils/snippets/snippets' |
| 6 | 6 | import type { Dispatch, PropsWithChildren, SetStateAction } from 'react' |
| 7 | 7 | import type { ScreenNotice } from '../../../types/ScreenNotice' |
| 8 | 8 | import type { Snippet } from '../../../types/Snippet' |
| 9 | -import type { CodeEditorInstance } from '../../../types/WordPressCodeEditor' | |
| 9 | +import type { CodeEditorInstance } from '../../../types/vendor/WordPressCodeEditor' | |
| 10 | 10 | |
| 11 | 11 | export interface SnippetFormContext { |
| 12 | 12 | snippet: Snippet |
| 13 | 13 | isWorking: boolean |
| 14 | 14 | isReadOnly: boolean |
| 15 | + isDirty: boolean | |
| 15 | 16 | setSnippet: Dispatch<SetStateAction<Snippet>> |
| 17 | + acceptSnippet: (snippet: Snippet) => void | |
| 16 | 18 | updateSnippet: Dispatch<SetStateAction<Snippet>> |
| 17 | 19 | setIsWorking: Dispatch<SetStateAction<boolean>> |
| 18 | 20 | currentNotice: ScreenNotice | undefined |
| 19 | 21 | setCurrentNotice: Dispatch<SetStateAction<ScreenNotice | undefined>> |
| @@ -27,10 +29,32 @@ | ||
| 27 | 29 | export interface WithSnippetFormContextProps extends PropsWithChildren { |
| 28 | 30 | initialSnippet: () => Snippet |
| 29 | 31 | } |
| 30 | 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 | + | |
| 31 | 53 | export const WithSnippetFormContext: React.FC<WithSnippetFormContextProps> = ({ children, initialSnippet }) => { |
| 32 | - const [snippet, setSnippet] = useState<Snippet>(initialSnippet) | |
| 54 | + const [initialValue] = useState<Snippet>(initialSnippet) | |
| 55 | + const [snippet, setSnippet] = useState<Snippet>(initialValue) | |
| 56 | + const [savedSnippet, setSavedSnippet] = useState<Snippet>(initialValue) | |
| 33 | 57 | const [isWorking, setIsWorking] = useState(false) |
| 34 | 58 | const [currentNotice, setCurrentNotice] = useState<ScreenNotice>() |
| 35 | 59 | const [codeEditorInstance, setCodeEditorInstance] = useState<CodeEditorInstance>() |
| 36 | 60 | |
| @@ -37,8 +61,16 @@ | ||
| 37 | 61 | const isReadOnly = useMemo( |
| 38 | 62 | () => snippet.locked || !isLicensed() && isProSnippet({ scope: snippet.scope }), |
| 39 | 63 | [snippet.locked, snippet.scope] |
| 40 | 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 | + }, []) | |
| 41 | 73 | |
| 42 | 74 | const handleRequestError = useCallback((error: unknown, message?: string) => { |
| 43 | 75 | console.error('Request failed', error) |
| 44 | 76 | setIsWorking(false) |
| @@ -57,9 +89,11 @@ | ||
| 57 | 89 | const value: SnippetFormContext = { |
| 58 | 90 | snippet, |
| 59 | 91 | isWorking, |
| 60 | 92 | isReadOnly, |
| 93 | + isDirty, | |
| 61 | 94 | setSnippet, |
| 95 | + acceptSnippet, | |
| 62 | 96 | setIsWorking, |
| 63 | 97 | updateSnippet, |
| 64 | 98 | currentNotice, |
| 65 | 99 | setCurrentNotice, |