UNPKG

@wordpress/block-library

Version:
150 lines (137 loc) 5.02 kB
/** * WordPress dependencies */ import { useState, useEffect, useMemo } from '@wordpress/element'; import { useSelect } from '@wordpress/data'; import { store as blockEditorStore } from '@wordpress/block-editor'; import { addQueryArgs } from '@wordpress/url'; import apiFetch from '@wordpress/api-fetch'; // This is limited by WP REST API const MAX_COMMENTS_PER_PAGE = 100; /** * Return an object with the query args needed to fetch the default page of * comments. * * @param {Object} props Hook props. * @param {number} props.postId ID of the post that contains the comments. * discussion settings. * * @return {Object} Query args to retrieve the comments. */ export const useCommentQueryArgs = _ref => { let { postId } = _ref; // Initialize the query args that are not going to change. const queryArgs = { status: 'approve', order: 'asc', context: 'embed', parent: 0, _embed: 'children' }; // Get the Discussion settings that may be needed to query the comments. const { pageComments, commentsPerPage, defaultCommentsPage: defaultPage } = useSelect(select => { const { getSettings } = select(blockEditorStore); const { __experimentalDiscussionSettings } = getSettings(); return __experimentalDiscussionSettings; }); // WP REST API doesn't allow fetching more than max items limit set per single page of data. // As for the editor performance is more important than completeness of data and fetching only the // max allowed for single page should be enough for the purpose of design and laying out the page. // Fetching over the limit would return an error here but would work with backend query. const perPage = pageComments ? Math.min(commentsPerPage, MAX_COMMENTS_PER_PAGE) : MAX_COMMENTS_PER_PAGE; // Get the number of the default page. const page = useDefaultPageIndex({ defaultPage, postId, perPage, queryArgs }); // Merge, memoize and return all query arguments, unless the default page's // number is not known yet. return useMemo(() => { return page ? { ...queryArgs, post: postId, per_page: perPage, page } : null; }, [postId, perPage, page]); }; /** * Return the index of the default page, depending on whether `defaultPage` is * `newest` or `oldest`. In the first case, the only way to know the page's * index is by using the `X-WP-TotalPages` header, which forces to make an * additional request. * * @param {Object} props Hook props. * @param {string} props.defaultPage Page shown by default (newest/oldest). * @param {number} props.postId ID of the post that contains the comments. * @param {number} props.perPage The number of comments included per page. * @param {Object} props.queryArgs Other query args. * * @return {number} Index of the default comments page. */ const useDefaultPageIndex = _ref2 => { let { defaultPage, postId, perPage, queryArgs } = _ref2; // Store the default page indices. const [defaultPages, setDefaultPages] = useState({}); const key = `${postId}_${perPage}`; const page = defaultPages[key] || 0; useEffect(() => { // Do nothing if the page is already known or not the newest page. if (page || defaultPage !== 'newest') { return; } // We need to fetch comments to know the index. Use HEAD and limit // fields just to ID, to make this call as light as possible. apiFetch({ path: addQueryArgs('/wp/v2/comments', { ...queryArgs, post: postId, per_page: perPage, _fields: 'id' }), method: 'HEAD', parse: false }).then(res => { const pages = parseInt(res.headers.get('X-WP-TotalPages')); setDefaultPages({ ...defaultPages, [key]: pages <= 1 ? 1 : pages // If there are 0 pages, it means that there are no comments, but there is no 0th page. }); }); }, [defaultPage, postId, perPage, setDefaultPages]); // The oldest one is always the first one. return defaultPage === 'newest' ? page : 1; }; /** * Generate a tree structure of comment IDs from a list of comment entities. The * children of each comment are obtained from `_embedded`. * * @typedef {{ commentId: number, children: CommentNode }} CommentNode * * @param {Object[]} topLevelComments List of comment entities. * @return {{ commentTree: CommentNode[]}} Tree of comment IDs. */ export const useCommentTree = topLevelComments => { const commentTree = useMemo(() => topLevelComments === null || topLevelComments === void 0 ? void 0 : topLevelComments.map(_ref3 => { let { id, _embedded } = _ref3; const [children] = (_embedded === null || _embedded === void 0 ? void 0 : _embedded.children) || [[]]; return { commentId: id, children: children.map(child => ({ commentId: child.id })) }; }), [topLevelComments]); return commentTree; }; //# sourceMappingURL=hooks.js.map