| 1 |
import { __, sprintf } from '@wordpress/i18n' |
| 2 |
import { createInterpolateElement } from '@wordpress/element' |
| 3 |
import React, { useState } from 'react' |
| 4 |
import classnames from 'classnames' |
| 5 |
import { WithRestAPIContext } from '../../../hooks/useRestAPI' |
| 6 |
import { WithSnippetsAPIContext } from '../../../hooks/useSnippetsAPI' |
| 7 |
import { WithSnippetsListContext } from '../../../hooks/useSnippetsList' |
| 8 |
import { SNIPPET_TYPES } from '../../../types/Snippet' |
| 9 |
import { isLicensed } from '../../../utils/screen' |
| 10 |
import { SNIPPET_TYPE_LABELS, getSnippetEditUrl, isProType } from '../../../utils/snippets/snippets' |
| 11 |
import { buildUrl } from '../../../utils/urls' |
| 12 |
import { Badge } from '../../common/Badge' |
| 13 |
import { Button } from '../../common/Button' |
| 14 |
import { Notice } from '../../common/Notice' |
| 15 |
import { UpsellDialog } from '../../common/UpsellDialog' |
| 16 |
import { WithSnippetsTableFilters, useSnippetsFilters } from './WithSnippetsTableFilters' |
| 17 |
import { WithFilteredSnippetsContext } from './WithFilteredSnippetsContext' |
| 18 |
import { SnippetsListTable } from './SnippetsListTable' |
| 19 |
import type { SnippetType } from '../../../types/Snippet' |
| 20 |
|
| 21 |
interface SnippetTypeTabProps { |
| 22 |
type?: SnippetType |
| 23 |
setIsUpgradeDialogOpen: (isOpen: boolean) => void |
| 24 |
} |
| 25 |
|
| 26 |
const SnippetTypeTab: React.FC<SnippetTypeTabProps> = ({ type, setIsUpgradeDialogOpen }) => { |
| 27 |
const { currentType, setCurrentType } = useSnippetsFilters() |
| 28 |
const tabName = type ?? 'all' |
| 29 |
|
| 30 |
return ( |
| 31 |
<a |
| 32 |
href={buildUrl(window.location.href, { type: tabName })} |
| 33 |
className={classnames('nav-tab', `${tabName}-tab`, { |
| 34 |
'nav-tab-active': type === currentType, |
| 35 |
'nav-tab-inactive': type && type !== currentType && !isLicensed() && isProType(type) |
| 36 |
})} |
| 37 |
aria-current={type === currentType ? 'page' : undefined} |
| 38 |
onClick={event => { |
| 39 |
event.preventDefault() |
| 40 |
|
| 41 |
if (type && !isLicensed() && isProType(type)) { |
| 42 |
setIsUpgradeDialogOpen(true) |
| 43 |
} else { |
| 44 |
setCurrentType(type) |
| 45 |
} |
| 46 |
}} |
| 47 |
> |
| 48 |
<span className={`${tabName}-label`}> |
| 49 |
{type ? SNIPPET_TYPE_LABELS[type] : __('All Snippets', 'code-snippets')} |
| 50 |
</span> |
| 51 |
{type && <Badge name={type} /> |
| 52 |
} |
| 53 |
</a> |
| 54 |
) |
| 55 |
} |
| 56 |
|
| 57 |
const PageHeading = () => { |
| 58 |
const { searchQueryText, searchLineNumber, currentTag, setSearchQuery, setCurrentTag } = useSnippetsFilters() |
| 59 |
return ( |
| 60 |
<> |
| 61 |
<a href={getSnippetEditUrl()} className="button button-primary button-large create-snippet-button"> |
| 62 |
{__('Create new snippet', 'code-snippets')} |
| 63 |
</a> |
| 64 |
|
| 65 |
<h2> |
| 66 |
{__('Manage Code Snippets', 'code-snippets')} |
| 67 |
|
| 68 |
{searchQueryText || currentTag |
| 69 |
? <span className="subtitle"> |
| 70 |
{__('Search results', 'code-snippets')} |
| 71 |
|
| 72 |
{/* translators: %s: search query. */} |
| 73 |
{searchQueryText && sprintf(__(' for “%s”', 'code-snippets'), searchQueryText)} |
| 74 |
|
| 75 |
{/* translators: %d: code line number. */} |
| 76 |
{searchLineNumber && sprintf(__(' on line “%d”', 'code-snippets'), searchLineNumber)} |
| 77 |
|
| 78 |
{/* translators: %s: tag name. */} |
| 79 |
{currentTag && sprintf(__(' in tag “%s”', 'code-snippets'), currentTag)} |
| 80 |
|
| 81 |
{' '} |
| 82 |
<Button small className="clear-filters" onClick={() => { |
| 83 |
setSearchQuery() |
| 84 |
setCurrentTag() |
| 85 |
}}> |
| 86 |
{__('Clear Filters', 'code-snippets')} |
| 87 |
</Button> |
| 88 |
</span> |
| 89 |
: null} |
| 90 |
</h2> |
| 91 |
|
| 92 |
<hr className="wp-header-end" /> |
| 93 |
|
| 94 |
<SafeModeNotice /> |
| 95 |
</> |
| 96 |
) |
| 97 |
} |
| 98 |
|
| 99 |
const SafeModeNotice = () => |
| 100 |
window.CODE_SNIPPETS_MANAGE?.isSafeModeActive |
| 101 |
? <Notice type="error"> |
| 102 |
<p> |
| 103 |
<strong>{__('Warning:', 'code-snippets')}</strong>{'\n'} |
| 104 |
{__('Safe mode is active and snippets will not execute!', 'code-snippets')}{'\n'} |
| 105 |
|
| 106 |
{createInterpolateElement( |
| 107 |
__('Remove the <code>CODE_SNIPPETS_SAFE_MODE</code> constant from <code>wp-config.php</code> file to turn off safe mode.', 'code-snippets'), |
| 108 |
{ |
| 109 |
code: <code /> |
| 110 |
} |
| 111 |
)}{'\n'} |
| 112 |
|
| 113 |
<a href="https://codesnippets.pro/doc/safe-mode" target="_blank" rel="noreferrer"> |
| 114 |
{__('Read more', 'code-snippets')} |
| 115 |
</a> |
| 116 |
</p> |
| 117 |
</Notice> |
| 118 |
: null |
| 119 |
|
| 120 |
const SnippetsTableInner = () => { |
| 121 |
const [isUpgradeDialogOpen, setIsUpgradeDialogOpen] = useState(false) |
| 122 |
|
| 123 |
return ( |
| 124 |
<> |
| 125 |
<PageHeading /> |
| 126 |
|
| 127 |
<nav |
| 128 |
className="nav-tab-wrapper snippet-type-tabs" |
| 129 |
aria-label={__('Snippet types', 'code-snippets')} |
| 130 |
> |
| 131 |
<SnippetTypeTab setIsUpgradeDialogOpen={setIsUpgradeDialogOpen} /> |
| 132 |
{SNIPPET_TYPES.map(type => |
| 133 |
<SnippetTypeTab key={type} type={type} setIsUpgradeDialogOpen={setIsUpgradeDialogOpen} />)} |
| 134 |
</nav> |
| 135 |
|
| 136 |
<WithFilteredSnippetsContext> |
| 137 |
<SnippetsListTable /> |
| 138 |
</WithFilteredSnippetsContext> |
| 139 |
|
| 140 |
<UpsellDialog isOpen={isUpgradeDialogOpen} setIsOpen={setIsUpgradeDialogOpen} /> |
| 141 |
</> |
| 142 |
) |
| 143 |
} |
| 144 |
|
| 145 |
export const SnippetsTable: React.FC = () => |
| 146 |
<WithRestAPIContext> |
| 147 |
<WithSnippetsAPIContext> |
| 148 |
<WithSnippetsListContext> |
| 149 |
<WithSnippetsTableFilters> |
| 150 |
<SnippetsTableInner /> |
| 151 |
</WithSnippetsTableFilters> |
| 152 |
</WithSnippetsListContext> |
| 153 |
</WithSnippetsAPIContext> |
| 154 |
</WithRestAPIContext> |
| 155 |
|