193 lines
6.3 KiB
TypeScript
193 lines
6.3 KiB
TypeScript
import React, { useState } from 'react'
|
|
import classnames from 'classnames'
|
|
import { __ } from '@wordpress/i18n'
|
|
import { addQueryArgs } from '@wordpress/url'
|
|
import { WithRestAPIContext } from '../../hooks/useRestAPI'
|
|
import { WithSnippetsListContext, useSnippetsList } from '../../hooks/useSnippetsList'
|
|
import { SubmitSnippetAction, useSubmitSnippet } from '../../hooks/useSubmitSnippet'
|
|
import { handleUnknownError } from '../../utils/errors'
|
|
import { createSnippetObject, getSnippetType, isCondition, validateSnippet } from '../../utils/snippets/snippets'
|
|
import { WithSnippetFormContext, useSnippetForm } from '../../hooks/useSnippetForm'
|
|
import { ConfirmDialog } from '../common/ConfirmDialog'
|
|
import { UpsellDialog } from '../common/UpsellDialog'
|
|
import { EditorSidebar } from '../EditorSidebar'
|
|
import { UpsellBanner } from '../common/UpsellBanner'
|
|
import { SnippetTypeInput } from './fields/SnippetTypeInput'
|
|
import { TagsEditor } from './fields/TagsEditor'
|
|
import { CodeEditor } from './fields/CodeEditor'
|
|
import { DescriptionEditor } from './fields/DescriptionEditor'
|
|
import { NameInput } from './fields/NameInput'
|
|
import { PageHeading } from './page/PageHeading'
|
|
import type { PropsWithChildren } from 'react'
|
|
import type { Snippet } from '../../types/Snippet'
|
|
|
|
const editFormClassName = ({ snippet, isReadOnly, isExpanded }: {
|
|
snippet: Snippet,
|
|
isReadOnly: boolean,
|
|
isExpanded: boolean
|
|
}) =>
|
|
classnames(
|
|
'snippet-form',
|
|
isExpanded ? 'snippet-form-expanded' : 'snippet-form-collapsed',
|
|
`${snippet.scope}-snippet`,
|
|
`${getSnippetType(snippet)}-snippet`,
|
|
`${snippet.id ? 'saved' : 'new'}-snippet`,
|
|
`${snippet.active ? 'active' : 'inactive'}-snippet`,
|
|
{
|
|
'erroneous-snippet': !!snippet.code_error,
|
|
'read-only-snippet': isReadOnly
|
|
}
|
|
)
|
|
|
|
interface ConfirmSubmitDialogProps {
|
|
doSubmit: (action: SubmitSnippetAction | undefined) => void
|
|
submitAction: SubmitSnippetAction | undefined
|
|
setSubmitAction: (action: SubmitSnippetAction | undefined) => void
|
|
validationWarning: string | undefined
|
|
setValidationWarning: (warning: string | undefined) => void
|
|
}
|
|
|
|
const ConfirmSubmitDialog: React.FC<ConfirmSubmitDialogProps> = ({
|
|
doSubmit,
|
|
submitAction,
|
|
setSubmitAction,
|
|
validationWarning,
|
|
setValidationWarning
|
|
}) =>
|
|
<ConfirmDialog
|
|
open={validationWarning !== undefined}
|
|
title={__('Snippet incomplete', 'code-snippets')}
|
|
confirmLabel={__('Continue', 'code-snippets')}
|
|
onCancel={() => {
|
|
setSubmitAction(undefined)
|
|
setValidationWarning(undefined)
|
|
}}
|
|
onConfirm={() => {
|
|
doSubmit(submitAction)
|
|
setSubmitAction(undefined)
|
|
setValidationWarning(undefined)
|
|
}}
|
|
>
|
|
<p>{`${validationWarning} ${__('Continue?', 'code-snippets')}`}</p>
|
|
</ConfirmDialog>
|
|
|
|
interface EditFormProps extends PropsWithChildren {
|
|
className?: string
|
|
}
|
|
|
|
const EditForm: React.FC<EditFormProps> = ({ children, className }) => {
|
|
const { submitSnippet } = useSubmitSnippet()
|
|
const { snippet } = useSnippetForm()
|
|
const { refreshSnippetsList } = useSnippetsList()
|
|
|
|
const [validationWarning, setValidationWarning] = useState<string | undefined>()
|
|
const [submitAction, setSubmitAction] = useState<SubmitSnippetAction | undefined>()
|
|
|
|
const doSubmit = (action?: SubmitSnippetAction) => {
|
|
submitSnippet(action)
|
|
.then(response => {
|
|
if (response && 0 !== response.id && window.CODE_SNIPPETS) {
|
|
if (window.location.href.toString().includes(window.CODE_SNIPPETS.urls.addNew)) {
|
|
document.title = document.title
|
|
.replace(__('Add New Snippet', 'code-snippets'), __('Edit Snippet', 'code-snippets'))
|
|
.replace(__('Add New Condition', 'code-snippets'), __('Edit Condition', 'code-snippets'))
|
|
|
|
const newUrl = addQueryArgs(window.CODE_SNIPPETS.urls.edit, { id: response.id })
|
|
window.history.pushState({}, document.title, newUrl)
|
|
}
|
|
}
|
|
})
|
|
.then(refreshSnippetsList)
|
|
.catch(handleUnknownError)
|
|
}
|
|
|
|
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
|
event.preventDefault()
|
|
|
|
const action = Object.values(SubmitSnippetAction).find(actionName =>
|
|
actionName === document.activeElement?.getAttribute('name'))
|
|
|
|
const validationWarning = validateSnippet(snippet)
|
|
|
|
if (validationWarning) {
|
|
setValidationWarning(validationWarning)
|
|
setSubmitAction(action)
|
|
} else {
|
|
doSubmit(action)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<form id="snippet-form" method="post" onSubmit={handleSubmit} className={className}>
|
|
{children}
|
|
</form>
|
|
|
|
<ConfirmSubmitDialog {...{ doSubmit, submitAction, setSubmitAction, validationWarning, setValidationWarning }} />
|
|
</>
|
|
)
|
|
}
|
|
|
|
const ConditionsEditor: React.FC = () => {
|
|
const { snippet } = useSnippetForm()
|
|
|
|
return isCondition(snippet)
|
|
? <div id="snippet_conditions" className="snippet-condition-editor-container">
|
|
<p>{__('This snippet type is not supported in this version of Code Snippets.')}</p>
|
|
</div>
|
|
: null
|
|
}
|
|
|
|
const EditFormWrap: React.FC = () => {
|
|
const { snippet, isReadOnly } = useSnippetForm()
|
|
const [isExpanded, setIsExpanded] = useState(false)
|
|
const [isUpgradeDialogOpen, setIsUpgradeDialogOpen] = useState(false)
|
|
|
|
return (
|
|
<div className="wrap">
|
|
<p><small className="cs-back">
|
|
{isCondition(snippet)
|
|
? <a href={addQueryArgs(window.CODE_SNIPPETS?.urls.manage, { type: 'cond' })}>
|
|
{__('Back to all conditions', 'code-snippets')}
|
|
</a>
|
|
: <a href={window.CODE_SNIPPETS?.urls.manage}>
|
|
{__('Back to all snippets', 'code-snippets')}
|
|
</a>}
|
|
</small></p>
|
|
|
|
<PageHeading />
|
|
|
|
<EditForm className={editFormClassName({ snippet, isReadOnly, isExpanded })}>
|
|
<main className="snippet-form-upper">
|
|
<div className="snippet-name-wrapper">
|
|
<NameInput />
|
|
<SnippetTypeInput setIsUpgradeDialogOpen={setIsUpgradeDialogOpen} />
|
|
</div>
|
|
|
|
<CodeEditor {...{ isExpanded, setIsExpanded }} />
|
|
<ConditionsEditor />
|
|
</main>
|
|
|
|
<div className="snippet-form-lower">
|
|
<UpsellBanner />
|
|
<DescriptionEditor />
|
|
<TagsEditor />
|
|
</div>
|
|
|
|
<EditorSidebar setIsUpgradeDialogOpen={setIsUpgradeDialogOpen} />
|
|
</EditForm>
|
|
|
|
<UpsellDialog isOpen={isUpgradeDialogOpen} setIsOpen={setIsUpgradeDialogOpen} />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export const SnippetForm: React.FC = () =>
|
|
<WithRestAPIContext>
|
|
<WithSnippetsListContext>
|
|
<WithSnippetFormContext initialSnippet={() => createSnippetObject(window.CODE_SNIPPETS_EDIT?.snippet)}>
|
|
<EditFormWrap />
|
|
</WithSnippetFormContext>
|
|
</WithSnippetsListContext>
|
|
</WithRestAPIContext>
|