| 1 |
/* REST helpers for the Sample Docs flow. Works from both the dashboard |
| 2 |
(betterdocs_admin.ai_sample_docs) and the quick-setup wizard |
| 3 |
(betterdocsSampleDocs). */ |
| 4 |
|
| 5 |
function cfg() { |
| 6 |
if (typeof window !== "undefined") { |
| 7 |
if (window.betterdocs_admin?.ai_sample_docs) { |
| 8 |
return { |
| 9 |
base: window.betterdocs_admin.ai_sample_docs.rest_base, |
| 10 |
restUrl: window.betterdocs_admin.rest_url, |
| 11 |
nonce: window.betterdocs_admin.nonce, |
| 12 |
enabled: !!window.betterdocs_admin.ai_sample_docs.enabled, |
| 13 |
}; |
| 14 |
} |
| 15 |
if (window.betterdocsSampleDocs) { |
| 16 |
return { |
| 17 |
base: window.betterdocsSampleDocs.rest_base, |
| 18 |
restUrl: window.betterdocsSampleDocs.rest_url, |
| 19 |
nonce: window.betterdocsSampleDocs.nonce, |
| 20 |
enabled: !!window.betterdocsSampleDocs.enabled, |
| 21 |
}; |
| 22 |
} |
| 23 |
} |
| 24 |
return { base: "", restUrl: "/wp-json/", nonce: "", enabled: false }; |
| 25 |
} |
| 26 |
|
| 27 |
/* Fetch the doc categories that already have docs, grouped for the read-only |
| 28 |
grid: [{ id, name, icon, color, articles:[titles] }]. Returns [] on any error. */ |
| 29 |
export async function fetchExistingDocs() { |
| 30 |
const { restUrl, nonce } = cfg(); |
| 31 |
const headers = nonce ? { "X-WP-Nonce": nonce } : {}; |
| 32 |
try { |
| 33 |
const [cats, grouped] = await Promise.all([ |
| 34 |
wp.apiFetch({ url: `${restUrl}wp/v2/doc_category?per_page=100&orderby=count&order=desc`, headers }), |
| 35 |
wp.apiFetch({ url: `${restUrl}betterdocs/v1/doc-categories?per_page=100`, headers }), |
| 36 |
]); |
| 37 |
const data = (grouped && grouped.data) || {}; |
| 38 |
return (Array.isArray(cats) ? cats : []) |
| 39 |
.map((c) => ({ |
| 40 |
id: "cat_" + c.id, |
| 41 |
name: c.name, |
| 42 |
icon: "book", |
| 43 |
color: "#00B884", |
| 44 |
articles: (data[c.id] || []).map((d) => (typeof d?.title === "string" ? d.title : d?.title?.rendered || "")), |
| 45 |
})) |
| 46 |
.filter((c) => c.articles.length > 0); |
| 47 |
} catch (e) { |
| 48 |
return []; |
| 49 |
} |
| 50 |
} |
| 51 |
|
| 52 |
async function call(endpoint, data) { |
| 53 |
const { base, nonce } = cfg(); |
| 54 |
const res = await wp.apiFetch({ |
| 55 |
url: `${base}/${endpoint}`, |
| 56 |
method: "POST", |
| 57 |
headers: nonce ? { "X-WP-Nonce": nonce } : {}, |
| 58 |
data, |
| 59 |
}); |
| 60 |
// BaseAPI::success() wraps payloads as { success, data }. |
| 61 |
return res && typeof res === "object" && "data" in res ? res.data : res; |
| 62 |
} |
| 63 |
|
| 64 |
export const sampleDocsEnabled = () => cfg().enabled; |
| 65 |
|
| 66 |
export const detectSite = (contentType) => call("detect", { content_type: contentType }); |
| 67 |
|
| 68 |
export const generateDocs = (payload) => call("generate", payload); |
| 69 |
|
| 70 |
/* Deep KB (docs): step 1 designs the whole information architecture. */ |
| 71 |
export const generateOutline = (payload) => call("outline", payload); |
| 72 |
|
| 73 |
/* Deep KB (docs): step 2 expands one article of the issued outline. */ |
| 74 |
export const generateArticle = (payload) => call("article", payload); |
| 75 |
|
| 76 |
export const insertDocs = (payload) => call("insert", payload); |
| 77 |
|
| 78 |
export const undoDocs = (contentType) => call("undo", { content_type: contentType }); |
| 79 |
|