PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.9.5
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.9.5
4.9.5 4.9.4 4.9.3 4.9.2 4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 All 203 releases
betterdocs / react-src / admin / dashboard / components / GridQuickEdit.js

GridQuickEdit.js in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 4.9.5, at react-src/admin/dashboard/components/GridQuickEdit.js

394 lines 18.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import React, { useEffect, useState } from "react";
2 import { IconClose } from "../../../icons";
3 import { useDashboardContext } from "../DashboardContext";
4 import MultiSelect from "./MultiSelect";
5 import { __ } from "@wordpress/i18n";
6 import Select from "react-select";
7 import { applyFilters } from "@wordpress/hooks";
8 import { toast } from "react-toastify";
9 import { decodeEntities } from "@wordpress/html-entities";
10 import useDebounce from "../hooks/useDebounce";
11 import { addQueryArgs } from "@wordpress/url";
12 import { useQuery } from "@tanstack/react-query";
13 import apiFetch from "@wordpress/api-fetch";
14 import useAuthorsQuery from "../hooks/useAuthorsQuery";
15 import useAuthorsSearchQuery from "../hooks/useAuthorsSearchQuery";
16
17 const GridQuickEdit = ({ data, setQuickEdit, setCategoriesPosts, docCategoriesQueryParams }) => {
18 const { docData, docId: selectedDocId, termId: selectedTermId } = data;
19 const [saveText, setSaveText] = useState("Save");
20 const [quickEditData, setQuickEditData] = useState({
21 author: "",
22 title: "",
23 slug: "",
24 comment_status: "",
25 status: "",
26 date: "",
27 password: "",
28 });
29 const [currentDocUser, setCurrentDocUser] = useState({});
30
31 const { usersLoading, authors, authorParams, setAuthorParams, isNextPageAvailable } = useAuthorsQuery('authors', {
32 per_page:10,
33 page:1
34 });
35
36 const { searchLoading, searchedUsers, setUserSearchValue } = useAuthorsSearchQuery();
37 const [privacyOption, setPrivacyOption] = useState("");
38
39 useEffect(() => {
40 setQuickEditData({
41 author: docData?.author,
42 title: docData.title,
43 slug: docData.slug,
44 comment_status: docData.comment_status,
45 status: docData.status,
46 date: docData?.date,
47 password: docData?.password,
48 });
49 setCurrentDocUser({
50 value: docData.author,
51 label: docData.author_info.name,
52 });
53 if (docData.status == "private") {
54 setPrivacyOption("private");
55 } else if (docData?.content?.protected || docData?.password?.length > 0) {
56 setPrivacyOption("password");
57 } else {
58 setPrivacyOption("none");
59 }
60 }, [docData]);
61
62 const statusOptions = [
63 { value: "publish", label: __("Published", "betterdocs") },
64 { value: "pending", label: __("Pending review", "betterdocs") },
65 { value: "draft", label: __("Draft", "betterdocs") },
66 ];
67
68 return (
69 <div className="betterdocs-quick-edit-panel">
70 <div className="betterdocs-quick-edit-wrap">
71 <div className="betterdocs-quick-edit-header">
72 <h3 className="betterdocs-quick-edit-title">
73 {decodeEntities(quickEditData.title)}
74 </h3>
75 <div
76 onClick={() =>
77 setQuickEdit((prevState) => {
78 return { ...prevState, isOpen: !prevState.isOpen };
79 })
80 }
81 className="betterdocs-quick-edit-close"
82 >
83 <svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
84 <path d="M1 1l12 12M13 1L1 13" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
85 </svg>
86 </div>
87 </div>
88 <div className="betterdocs-quick-edit-body">
89 <div className="betterdocs-quick-edit-form-group">
90 <label htmlFor="betterdocs-quick-edit-status">
91 {__("Authors:", "betterdocs")}
92 </label>
93 <Select
94 className="quick-edit-select-fields betterdocs-quick-edit-authors"
95 id="betterdocs-quick-edit-authors"
96 value={currentDocUser}
97 onInputChange={(e) => {
98 setUserSearchValue(e);
99 }}
100 onMenuScrollToBottom={(e) => {
101 if(e != null && isNextPageAvailable){
102 setAuthorParams((prev) => {
103 return {...prev, page:authorParams.page + 1}
104 })
105 }
106 }}
107 onChange={(selectedOption) => {
108 setQuickEditData((state) => ({
109 ...state,
110 author: selectedOption?.value,
111 }));
112 setCurrentDocUser(selectedOption);
113 }}
114 filterOption={(option, inputValue)=> {
115 return option;
116 }}
117 options={searchedUsers?.length > 0 ? searchedUsers : authors}
118 classNamePrefix="quick-edit-select-fields"
119 />
120 </div>
121 <div className="betterdocs-quick-edit-form-group">
122 <label htmlFor="betterdocs-quick-edit-status">
123 {__("Status:", "betterdocs")}
124 </label>
125 <Select
126 className="quick-edit-select-fields betterdocs-quick-edit-status"
127 id="betterdocs-quick-edit-status"
128 value={statusOptions.find(
129 (option) =>
130 option.value === quickEditData.status,
131 )}
132 onChange={(selectedOption) => {
133 setQuickEditData((state) => ({
134 ...state,
135 status: selectedOption?.value,
136 }));
137 }}
138 options={statusOptions}
139 classNamePrefix="quick-edit-select-fields"
140 />
141 </div>
142 <div className="betterdocs-quick-edit-form-group">
143 <label htmlFor="betterdocs-quick-edit-title">
144 {__("Title:", "betterdocs")}
145 </label>
146 <input
147 id="betterdocs-quick-edit-title"
148 type="text"
149 value={quickEditData.title}
150 onChange={(event) =>
151 setQuickEditData((state) => ({
152 ...state,
153 title: event.target.value,
154 }))
155 }
156 />
157 </div>
158 <div className="betterdocs-quick-edit-form-group">
159 <label htmlFor="betterdocs-quick-edit-slug">
160 {__("Slug", "betterdocs")}
161 </label>
162 <input
163 id="betterdocs-quick-edit-slug"
164 type="text"
165 placeholder="Slug"
166 value={quickEditData.slug}
167 onChange={(event) =>
168 setQuickEditData((state) => ({
169 ...state,
170 slug: event.target.value,
171 }))
172 }
173 />
174 </div>
175 <div className="betterdocs-quick-edit-form-group">
176 <label htmlFor="betterdocs-quick-date">
177 {__("Date:", "betterdocs")}
178 </label>
179 <input
180 id="betterdocs-quick-edit-date"
181 type="datetime-local"
182 placeholder="date"
183 value={quickEditData?.date}
184 onChange={(e) => {
185 setQuickEditData((state) => ({
186 ...state,
187 date: e?.target?.value,
188 }));
189 }}
190 />
191 </div>
192 <div className="betterdocs-quick-edit-form-group">
193 <label>{__("Select Privacy", "betterdocs")}</label>
194 <div className="betterdocs-quick-edit-privacy-radio">
195 <div className="betterdocs-quick-edit-privacy-radio-group">
196 <input
197 id="password"
198 type="radio"
199 name="privacy"
200 value="password"
201 checked={privacyOption === "password"}
202 onChange={(e) => {
203 setPrivacyOption(e.target.value);
204 const defaultData = {
205 ...quickEditData,
206 status: docData?.status
207 };
208 if( docData?.password?.length > 0 ) {
209 defaultData['password'] = docData?.password;
210 }
211 setQuickEditData((prev) => (defaultData));
212 }}
213 />
214 <label htmlFor="password">
215 {__("Password Protected", "betterdocs")}
216 </label>
217 </div>
218 <div className="betterdocs-quick-edit-privacy-radio-group">
219 <input
220 id="private"
221 type="radio"
222 name="privacy"
223 value="private"
224 checked={privacyOption === "private"}
225 onChange={(e) => {
226 setPrivacyOption(e.target.value);
227 if (
228 quickEditData?.hasOwnProperty(
229 "password",
230 )
231 ) {
232 delete quickEditData["password"];
233 }
234 setQuickEditData((prev) => ({
235 ...quickEditData,
236 status: "private",
237 }));
238 }}
239 />
240 <label htmlFor="private">
241 {__("Make Private", "betterdocs")}
242 </label>
243 </div>
244 <div className="betterdocs-quick-edit-privacy-radio-group">
245 <input
246 id="none"
247 type="radio"
248 name="privacy"
249 value="none"
250 checked={privacyOption === "none"}
251 onChange={(e) => {
252 setPrivacyOption(e.target.value);
253 setQuickEditData((prev) => ({
254 ...quickEditData,
255 title: quickEditData?.title?.replace(
256 "Private:",
257 "",
258 ),
259 status: "publish",
260 password:""
261 }));
262 }}
263 />
264 <label htmlFor="none">
265 {__("None", "betterdocs")}
266 </label>
267 </div>
268 </div>
269 </div>
270 {privacyOption === "password" && (
271 <div className="betterdocs-quick-edit-form-group betterdocs-quick-edit-password-field">
272 <label htmlFor="betterdocs-quick-edit-password">
273 {__("Password:", "betterdocs")}
274 </label>
275 <input
276 id="betterdocs-quick-edit-password"
277 type="text"
278 placeholder=""
279 value={
280 quickEditData?.password?.length > 0
281 ? quickEditData?.password
282 : ""
283 }
284 onChange={(e) => {
285 setQuickEditData((state) => ({
286 ...state,
287 status:
288 docData?.status == "private"
289 ? "publish"
290 : docData?.status,
291 password: e?.target?.value,
292 }));
293 }}
294 />
295 </div>
296 )}
297
298 {betterdocs_admin?.multiple_kb == 1 &&
299 applyFilters("quick_edit_mkb_filter", "", [
300 docData,
301 setQuickEditData,
302 MultiSelect,
303 ])}
304
305 <MultiSelect
306 name="doc_category"
307 endpoint="wp/v2/doc_category"
308 doc={docData}
309 setQuickEditData={setQuickEditData}
310 label={__("Category", "betterdocs")}
311 placeholder={__("Search Category", "betterdocs")}
312 />
313
314 <MultiSelect
315 name="doc_tag"
316 endpoint="wp/v2/doc_tag"
317 doc={docData}
318 setQuickEditData={setQuickEditData}
319 label={__("Tags", "betterdocs")}
320 placeholder={__("Search Tags", "betterdocs")}
321 />
322
323 <div className="betterdocs-quick-edit-form-group">
324 <div className="betterdocs-quick-edit-comments">
325 <input
326 type="checkbox"
327 id={docData.id}
328 checked={
329 quickEditData.comment_status === "open"
330 }
331 onChange={(event) =>
332 setQuickEditData((prev) => ({
333 ...prev,
334 comment_status: event.target.checked
335 ? "open"
336 : "closed",
337 }))
338 }
339 />
340 <label htmlFor={docData.id}>
341 {__("Allow Comments", "betterdocs")}
342 </label>
343 </div>
344 </div>
345 </div>
346 <div className="betterdocs-quick-edit-footer">
347 <div className="betterdocs-quick-edit-submit">
348 <button
349 type="button"
350 className="betterdocs-quick-edit-cancel-btn"
351 onClick={() =>
352 setQuickEdit((prevState) => {
353 return { ...prevState, isOpen: !prevState.isOpen };
354 })
355 }
356 >
357 {__("Cancel", "betterdocs")}
358 </button>
359 <button
360 type="submit"
361 className="betterdocs-quick-edit-submit-btn"
362 onClick={async (event) => {
363 event.preventDefault();
364 setSaveText("Saving...");
365 const response = await wp.apiFetch({
366 path: `/wp/v2/docs/${docData.id}`,
367 method: "POST",
368 data: quickEditData,
369 });
370 if (response != undefined) {
371 setCategoriesPosts.invalidateQueries(['docsCategories', docCategoriesQueryParams]); // refetch the updated query from the DB after update
372 setSaveText("Save");
373 toast.success(
374 __("Saved Successfully", "betterdocs"),
375 );
376 } else {
377 setSaveText("Save");
378 toast.error(
379 __("Error While Saving", "betterdocs"),
380 );
381 }
382 }}
383 >
384 {saveText}
385 </button>
386 </div>
387 </div>
388 </div>
389 </div>
390 );
391 };
392
393 export default GridQuickEdit;
394